blob: a60a6237d9b8d0aff9757f4e8e47b2ef463b1c4a [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
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
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005 *f
Owen Taylor3473f882001-02-23 17:55:21 +00006 * 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 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Nick Wellnhofera58331a2017-05-29 21:02:21 +020020#include <limits.h>
Owen Taylor3473f882001-02-23 17:55:21 +000021#include <string.h>
22
23#ifdef HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26#ifdef HAVE_MATH_H
27#include <math.h>
28#endif
29#ifdef HAVE_FLOAT_H
30#include <float.h>
31#endif
Owen Taylor3473f882001-02-23 17:55:21 +000032#ifdef HAVE_CTYPE_H
33#include <ctype.h>
34#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000035#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000037#endif
Owen Taylor3473f882001-02-23 17:55:21 +000038
39#include <libxml/xmlmemory.h>
40#include <libxml/tree.h>
41#include <libxml/valid.h>
42#include <libxml/xpath.h>
43#include <libxml/xpathInternals.h>
44#include <libxml/parserInternals.h>
45#include <libxml/hash.h>
46#ifdef LIBXML_XPTR_ENABLED
47#include <libxml/xpointer.h>
48#endif
49#ifdef LIBXML_DEBUG_ENABLED
50#include <libxml/debugXML.h>
51#endif
52#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000053#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000054#include <libxml/globals.h>
Daniel Veillard56de87e2005-02-16 00:22:29 +000055#ifdef LIBXML_PATTERN_ENABLED
56#include <libxml/pattern.h>
57#endif
58
Daniel Veillardade10f22012-07-12 09:43:27 +080059#include "buf.h"
60
Daniel Veillard56de87e2005-02-16 00:22:29 +000061#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000062#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000063#endif
Owen Taylor3473f882001-02-23 17:55:21 +000064
Daniel Veillard45490ae2008-07-29 09:13:19 +000065#define TODO \
Daniel Veillardd96f6d32003-10-07 21:25:12 +000066 xmlGenericError(xmlGenericErrorContext, \
67 "Unimplemented block at %s:%d\n", \
68 __FILE__, __LINE__);
69
Vojtech Fried3e031b72012-08-24 16:52:44 +080070/**
71 * WITH_TIM_SORT:
72 *
73 * Use the Timsort algorithm provided in timsort.h to sort
74 * nodeset as this is a great improvement over the old Shell sort
75 * used in xmlXPathNodeSetSort()
76 */
77#define WITH_TIM_SORT
78
William M. Brackd1757ab2004-10-02 22:07:48 +000079/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000080* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000081* If defined, this will use xmlXPathCmpNodesExt() instead of
82* xmlXPathCmpNodes(). The new function is optimized comparison of
83* non-element nodes; actually it will speed up comparison only if
84* xmlXPathOrderDocElems() was called in order to index the elements of
85* a tree in document order; Libxslt does such an indexing, thus it will
86* benefit from this optimization.
87*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000088#define XP_OPTIMIZED_NON_ELEM_COMPARISON
89
90/*
91* XP_OPTIMIZED_FILTER_FIRST:
92* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
93* in a way, that it stop evaluation at the first node.
Daniel Veillard45490ae2008-07-29 09:13:19 +000094*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000095#define XP_OPTIMIZED_FILTER_FIRST
96
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000097/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000098* XP_DEBUG_OBJ_USAGE:
99* Internal flag to enable tracking of how much XPath objects have been
100* created.
101*/
102/* #define XP_DEBUG_OBJ_USAGE */
103
104/*
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800105 * XPATH_MAX_STEPS:
106 * when compiling an XPath expression we arbitrary limit the maximum
107 * number of step operation in the compiled expression. 1000000 is
108 * an insanely large value which should never be reached under normal
109 * circumstances
110 */
111#define XPATH_MAX_STEPS 1000000
112
113/*
114 * XPATH_MAX_STACK_DEPTH:
115 * when evaluating an XPath expression we arbitrary limit the maximum
116 * number of object allowed to be pushed on the stack. 1000000 is
117 * an insanely large value which should never be reached under normal
118 * circumstances
119 */
120#define XPATH_MAX_STACK_DEPTH 1000000
121
122/*
123 * XPATH_MAX_NODESET_LENGTH:
124 * when evaluating an XPath expression nodesets are created and we
125 * arbitrary limit the maximum length of those node set. 10000000 is
126 * an insanely large value which should never be reached under normal
127 * circumstances, one would first need to construct an in memory tree
128 * with more than 10 millions nodes.
129 */
130#define XPATH_MAX_NODESET_LENGTH 10000000
131
132/*
William M. Brackd1757ab2004-10-02 22:07:48 +0000133 * TODO:
134 * There are a few spots where some tests are done which depend upon ascii
135 * data. These should be enhanced for full UTF8 support (see particularly
136 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
137 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000138
Denis Pauke28c8a12013-08-03 14:22:54 +0300139#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
140/**
141 * xmlXPathCmpNodesExt:
142 * @node1: the first node
143 * @node2: the second node
144 *
145 * Compare two nodes w.r.t document order.
146 * This one is optimized for handling of non-element nodes.
147 *
148 * Returns -2 in case of error 1 if first point < second point, 0 if
149 * it's the same node, -1 otherwise
150 */
151static int
152xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
153 int depth1, depth2;
154 int misc = 0, precedence1 = 0, precedence2 = 0;
155 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
156 xmlNodePtr cur, root;
157 long l1, l2;
158
159 if ((node1 == NULL) || (node2 == NULL))
160 return(-2);
161
162 if (node1 == node2)
163 return(0);
164
165 /*
166 * a couple of optimizations which will avoid computations in most cases
167 */
168 switch (node1->type) {
169 case XML_ELEMENT_NODE:
170 if (node2->type == XML_ELEMENT_NODE) {
171 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
172 (0 > (long) node2->content) &&
173 (node1->doc == node2->doc))
174 {
175 l1 = -((long) node1->content);
176 l2 = -((long) node2->content);
177 if (l1 < l2)
178 return(1);
179 if (l1 > l2)
180 return(-1);
181 } else
182 goto turtle_comparison;
183 }
184 break;
185 case XML_ATTRIBUTE_NODE:
186 precedence1 = 1; /* element is owner */
187 miscNode1 = node1;
188 node1 = node1->parent;
189 misc = 1;
190 break;
191 case XML_TEXT_NODE:
192 case XML_CDATA_SECTION_NODE:
193 case XML_COMMENT_NODE:
194 case XML_PI_NODE: {
195 miscNode1 = node1;
196 /*
197 * Find nearest element node.
198 */
199 if (node1->prev != NULL) {
200 do {
201 node1 = node1->prev;
202 if (node1->type == XML_ELEMENT_NODE) {
203 precedence1 = 3; /* element in prev-sibl axis */
204 break;
205 }
206 if (node1->prev == NULL) {
207 precedence1 = 2; /* element is parent */
208 /*
209 * URGENT TODO: Are there any cases, where the
210 * parent of such a node is not an element node?
211 */
212 node1 = node1->parent;
213 break;
214 }
215 } while (1);
216 } else {
217 precedence1 = 2; /* element is parent */
218 node1 = node1->parent;
219 }
220 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
221 (0 <= (long) node1->content)) {
222 /*
223 * Fallback for whatever case.
224 */
225 node1 = miscNode1;
226 precedence1 = 0;
227 } else
228 misc = 1;
229 }
230 break;
231 case XML_NAMESPACE_DECL:
232 /*
233 * TODO: why do we return 1 for namespace nodes?
234 */
235 return(1);
236 default:
237 break;
238 }
239 switch (node2->type) {
240 case XML_ELEMENT_NODE:
241 break;
242 case XML_ATTRIBUTE_NODE:
243 precedence2 = 1; /* element is owner */
244 miscNode2 = node2;
245 node2 = node2->parent;
246 misc = 1;
247 break;
248 case XML_TEXT_NODE:
249 case XML_CDATA_SECTION_NODE:
250 case XML_COMMENT_NODE:
251 case XML_PI_NODE: {
252 miscNode2 = node2;
253 if (node2->prev != NULL) {
254 do {
255 node2 = node2->prev;
256 if (node2->type == XML_ELEMENT_NODE) {
257 precedence2 = 3; /* element in prev-sibl axis */
258 break;
259 }
260 if (node2->prev == NULL) {
261 precedence2 = 2; /* element is parent */
262 node2 = node2->parent;
263 break;
264 }
265 } while (1);
266 } else {
267 precedence2 = 2; /* element is parent */
268 node2 = node2->parent;
269 }
270 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
Gauravfcd45832013-11-28 23:01:44 +0800271 (0 <= (long) node2->content))
Denis Pauke28c8a12013-08-03 14:22:54 +0300272 {
273 node2 = miscNode2;
274 precedence2 = 0;
275 } else
276 misc = 1;
277 }
278 break;
279 case XML_NAMESPACE_DECL:
280 return(1);
281 default:
282 break;
283 }
284 if (misc) {
285 if (node1 == node2) {
286 if (precedence1 == precedence2) {
287 /*
288 * The ugly case; but normally there aren't many
289 * adjacent non-element nodes around.
290 */
291 cur = miscNode2->prev;
292 while (cur != NULL) {
293 if (cur == miscNode1)
294 return(1);
295 if (cur->type == XML_ELEMENT_NODE)
296 return(-1);
297 cur = cur->prev;
298 }
299 return (-1);
300 } else {
301 /*
302 * Evaluate based on higher precedence wrt to the element.
303 * TODO: This assumes attributes are sorted before content.
304 * Is this 100% correct?
305 */
306 if (precedence1 < precedence2)
307 return(1);
308 else
309 return(-1);
310 }
311 }
312 /*
313 * Special case: One of the helper-elements is contained by the other.
314 * <foo>
315 * <node2>
316 * <node1>Text-1(precedence1 == 2)</node1>
317 * </node2>
318 * Text-6(precedence2 == 3)
319 * </foo>
320 */
321 if ((precedence2 == 3) && (precedence1 > 1)) {
322 cur = node1->parent;
323 while (cur) {
324 if (cur == node2)
325 return(1);
326 cur = cur->parent;
327 }
328 }
329 if ((precedence1 == 3) && (precedence2 > 1)) {
330 cur = node2->parent;
331 while (cur) {
332 if (cur == node1)
333 return(-1);
334 cur = cur->parent;
335 }
336 }
337 }
338
339 /*
340 * Speedup using document order if availble.
341 */
342 if ((node1->type == XML_ELEMENT_NODE) &&
343 (node2->type == XML_ELEMENT_NODE) &&
344 (0 > (long) node1->content) &&
345 (0 > (long) node2->content) &&
346 (node1->doc == node2->doc)) {
347
348 l1 = -((long) node1->content);
349 l2 = -((long) node2->content);
350 if (l1 < l2)
351 return(1);
352 if (l1 > l2)
353 return(-1);
354 }
355
356turtle_comparison:
357
358 if (node1 == node2->prev)
359 return(1);
360 if (node1 == node2->next)
361 return(-1);
362 /*
363 * compute depth to root
364 */
Nick Wellnhofer3eaedba2015-07-11 14:27:34 +0200365 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
366 if (cur->parent == node1)
Denis Pauke28c8a12013-08-03 14:22:54 +0300367 return(1);
368 depth2++;
369 }
370 root = cur;
Nick Wellnhofer3eaedba2015-07-11 14:27:34 +0200371 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
372 if (cur->parent == node2)
Denis Pauke28c8a12013-08-03 14:22:54 +0300373 return(-1);
374 depth1++;
375 }
376 /*
377 * Distinct document (or distinct entities :-( ) case.
378 */
379 if (root != cur) {
380 return(-2);
381 }
382 /*
383 * get the nearest common ancestor.
384 */
385 while (depth1 > depth2) {
386 depth1--;
387 node1 = node1->parent;
388 }
389 while (depth2 > depth1) {
390 depth2--;
391 node2 = node2->parent;
392 }
393 while (node1->parent != node2->parent) {
394 node1 = node1->parent;
395 node2 = node2->parent;
396 /* should not happen but just in case ... */
397 if ((node1 == NULL) || (node2 == NULL))
398 return(-2);
399 }
400 /*
401 * Find who's first.
402 */
403 if (node1 == node2->prev)
404 return(1);
405 if (node1 == node2->next)
406 return(-1);
407 /*
408 * Speedup using document order if availble.
409 */
410 if ((node1->type == XML_ELEMENT_NODE) &&
411 (node2->type == XML_ELEMENT_NODE) &&
412 (0 > (long) node1->content) &&
413 (0 > (long) node2->content) &&
414 (node1->doc == node2->doc)) {
415
416 l1 = -((long) node1->content);
417 l2 = -((long) node2->content);
418 if (l1 < l2)
419 return(1);
420 if (l1 > l2)
421 return(-1);
422 }
423
424 for (cur = node1->next;cur != NULL;cur = cur->next)
425 if (cur == node2)
426 return(1);
427 return(-1); /* assume there is no sibling list corruption */
428}
429#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
430
Vojtech Fried3e031b72012-08-24 16:52:44 +0800431/*
432 * Wrapper for the Timsort argorithm from timsort.h
433 */
434#ifdef WITH_TIM_SORT
435#define SORT_NAME libxml_domnode
436#define SORT_TYPE xmlNodePtr
437/**
438 * wrap_cmp:
439 * @x: a node
440 * @y: another node
441 *
442 * Comparison function for the Timsort implementation
443 *
Daniel Veillard510e7582012-09-04 11:50:36 +0800444 * Returns -2 in case of error -1 if first point < second point, 0 if
445 * it's the same node, +1 otherwise
Vojtech Fried3e031b72012-08-24 16:52:44 +0800446 */
447static
448int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
449#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Vojtech Fried3e031b72012-08-24 16:52:44 +0800450 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
451 {
452 int res = xmlXPathCmpNodesExt(x, y);
453 return res == -2 ? res : -res;
454 }
455#else
456 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
457 {
458 int res = xmlXPathCmpNodes(x, y);
459 return res == -2 ? res : -res;
460 }
461#endif
462#define SORT_CMP(x, y) (wrap_cmp(x, y))
463#include "timsort.h"
464#endif /* WITH_TIM_SORT */
465
William M. Brack21e4ef22005-01-02 09:53:13 +0000466#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000467
468/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000469 * *
470 * Floating point stuff *
471 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000472 ************************************************************************/
473
Daniel Veillardc0631a62001-09-20 13:56:06 +0000474#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000475#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000476#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000477#include "trionan.c"
478
Owen Taylor3473f882001-02-23 17:55:21 +0000479/*
Owen Taylor3473f882001-02-23 17:55:21 +0000480 * The lack of portability of this section of the libc is annoying !
481 */
482double xmlXPathNAN = 0;
483double xmlXPathPINF = 1;
484double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000485static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000486static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000487
Owen Taylor3473f882001-02-23 17:55:21 +0000488/**
489 * xmlXPathInit:
490 *
491 * Initialize the XPath environment
492 */
493void
494xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000495 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000496
Bjorn Reese45029602001-08-21 09:23:53 +0000497 xmlXPathPINF = trio_pinf();
498 xmlXPathNINF = trio_ninf();
499 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000500 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000501
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000502 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000503}
504
Daniel Veillardcda96922001-08-21 10:56:31 +0000505/**
506 * xmlXPathIsNaN:
507 * @val: a double value
508 *
509 * Provides a portable isnan() function to detect whether a double
510 * is a NotaNumber. Based on trio code
511 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000512 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000513 * Returns 1 if the value is a NaN, 0 otherwise
514 */
515int
516xmlXPathIsNaN(double val) {
517 return(trio_isnan(val));
518}
519
520/**
521 * xmlXPathIsInf:
522 * @val: a double value
523 *
524 * Provides a portable isinf() function to detect whether a double
525 * is a +Infinite or -Infinite. Based on trio code
526 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000527 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000528 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
529 */
530int
531xmlXPathIsInf(double val) {
532 return(trio_isinf(val));
533}
534
Daniel Veillard4432df22003-09-28 18:58:27 +0000535#endif /* SCHEMAS or XPATH */
536#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000537/**
538 * xmlXPathGetSign:
539 * @val: a double value
540 *
541 * Provides a portable function to detect the sign of a double
542 * Modified from trio code
543 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000544 *
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000545 * Returns 1 if the value is Negative, 0 if positive
546 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000547static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000548xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000549 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000550}
551
552
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000553/*
554 * TODO: when compatibility allows remove all "fake node libxslt" strings
555 * the test should just be name[0] = ' '
556 */
Daniel Veillard074f37e2008-09-01 13:38:22 +0000557#ifdef DEBUG_XPATH_EXPRESSION
558#define DEBUG_STEP
559#define DEBUG_EXPR
560#define DEBUG_EVAL_COUNTS
561#endif
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000562
563static xmlNs xmlXPathXMLNamespaceStruct = {
564 NULL,
565 XML_NAMESPACE_DECL,
566 XML_XML_NAMESPACE,
567 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000568 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000569 NULL
570};
571static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
572#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard45490ae2008-07-29 09:13:19 +0000573/*
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000574 * Optimizer is disabled only when threaded apps are detected while
575 * the library ain't compiled for thread safety.
576 */
577static int xmlXPathDisableOptimizer = 0;
578#endif
579
Owen Taylor3473f882001-02-23 17:55:21 +0000580/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000581 * *
582 * Error handling routines *
583 * *
584 ************************************************************************/
585
Daniel Veillard24505b02005-07-28 23:49:35 +0000586/**
587 * XP_ERRORNULL:
588 * @X: the error code
589 *
590 * Macro to raise an XPath error and return NULL.
591 */
592#define XP_ERRORNULL(X) \
593 { xmlXPathErr(ctxt, X); return(NULL); }
594
William M. Brack08171912003-12-29 02:52:11 +0000595/*
596 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
597 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000598static const char *xmlXPathErrorMessages[] = {
599 "Ok\n",
600 "Number encoding\n",
601 "Unfinished literal\n",
602 "Start of literal\n",
603 "Expected $ for variable reference\n",
604 "Undefined variable\n",
605 "Invalid predicate\n",
606 "Invalid expression\n",
607 "Missing closing curly brace\n",
608 "Unregistered function\n",
609 "Invalid operand\n",
610 "Invalid type\n",
611 "Invalid number of arguments\n",
612 "Invalid context size\n",
613 "Invalid context position\n",
614 "Memory allocation error\n",
615 "Syntax error\n",
616 "Resource error\n",
617 "Sub resource error\n",
618 "Undefined namespace prefix\n",
619 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000620 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000621 "Invalid or incomplete context\n",
Jan Pokorný75801652013-12-19 15:09:14 +0100622 "Stack usage error\n",
Daniel Veillard47881282012-09-07 14:24:50 +0800623 "Forbidden variable\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000624 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000625};
William M. Brackcd65bc92005-01-06 09:39:18 +0000626#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
627 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000628/**
629 * xmlXPathErrMemory:
630 * @ctxt: an XPath context
631 * @extra: extra informations
632 *
633 * Handle a redefinition of attribute error
634 */
635static void
636xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
637{
638 if (ctxt != NULL) {
639 if (extra) {
640 xmlChar buf[200];
641
642 xmlStrPrintf(buf, 200,
David Kilzer4472c3a2016-05-13 15:13:17 +0800643 "Memory allocation failed : %s\n",
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000644 extra);
645 ctxt->lastError.message = (char *) xmlStrdup(buf);
646 } else {
647 ctxt->lastError.message = (char *)
648 xmlStrdup(BAD_CAST "Memory allocation failed\n");
649 }
650 ctxt->lastError.domain = XML_FROM_XPATH;
651 ctxt->lastError.code = XML_ERR_NO_MEMORY;
652 if (ctxt->error != NULL)
653 ctxt->error(ctxt->userData, &ctxt->lastError);
654 } else {
655 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000656 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000657 NULL, NULL, XML_FROM_XPATH,
658 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
659 extra, NULL, NULL, 0, 0,
660 "Memory allocation failed : %s\n", extra);
661 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000662 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000663 NULL, NULL, XML_FROM_XPATH,
664 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
665 NULL, NULL, NULL, 0, 0,
666 "Memory allocation failed\n");
667 }
668}
669
670/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000671 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000672 * @ctxt: an XPath parser context
673 * @extra: extra informations
674 *
675 * Handle a redefinition of attribute error
676 */
677static void
678xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
679{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000680 if (ctxt == NULL)
681 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000682 else {
683 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000684 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000685 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000686}
687
688/**
689 * xmlXPathErr:
690 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000691 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000692 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000693 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000694 */
695void
696xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
697{
William M. Brackcd65bc92005-01-06 09:39:18 +0000698 if ((error < 0) || (error > MAXERRNO))
699 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000700 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000701 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000702 NULL, NULL, XML_FROM_XPATH,
703 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
704 XML_ERR_ERROR, NULL, 0,
705 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200706 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000707 return;
708 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000709 ctxt->error = error;
710 if (ctxt->context == NULL) {
711 __xmlRaiseError(NULL, NULL, NULL,
712 NULL, NULL, XML_FROM_XPATH,
713 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
714 XML_ERR_ERROR, NULL, 0,
715 (const char *) ctxt->base, NULL, NULL,
716 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200717 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000718 return;
719 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000720
721 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000722 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000723
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000724 ctxt->context->lastError.domain = XML_FROM_XPATH;
725 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
726 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000727 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000728 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
729 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
730 ctxt->context->lastError.node = ctxt->context->debugNode;
731 if (ctxt->context->error != NULL) {
732 ctxt->context->error(ctxt->context->userData,
733 &ctxt->context->lastError);
734 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000735 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000736 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
737 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
738 XML_ERR_ERROR, NULL, 0,
739 (const char *) ctxt->base, NULL, NULL,
740 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200741 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000742 }
743
744}
745
746/**
747 * xmlXPatherror:
748 * @ctxt: the XPath Parser context
749 * @file: the file name
750 * @line: the line number
751 * @no: the error number
752 *
753 * Formats an error message.
754 */
755void
756xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
757 int line ATTRIBUTE_UNUSED, int no) {
758 xmlXPathErr(ctxt, no);
759}
760
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000761/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000762 * *
763 * Utilities *
764 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000765 ************************************************************************/
766
767/**
768 * xsltPointerList:
769 *
770 * Pointer-list for various purposes.
771 */
772typedef struct _xmlPointerList xmlPointerList;
773typedef xmlPointerList *xmlPointerListPtr;
774struct _xmlPointerList {
775 void **items;
776 int number;
777 int size;
778};
779/*
780* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
781* and here, we should make the functions public.
782*/
783static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000784xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000785 void *item,
786 int initialSize)
787{
788 if (list->items == NULL) {
789 if (initialSize <= 0)
790 initialSize = 1;
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800791 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000792 if (list->items == NULL) {
793 xmlXPathErrMemory(NULL,
794 "xmlPointerListCreate: allocating item\n");
795 return(-1);
796 }
797 list->number = 0;
798 list->size = initialSize;
799 } else if (list->size <= list->number) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800800 if (list->size > 50000000) {
801 xmlXPathErrMemory(NULL,
802 "xmlPointerListAddSize: re-allocating item\n");
803 return(-1);
804 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000805 list->size *= 2;
806 list->items = (void **) xmlRealloc(list->items,
807 list->size * sizeof(void *));
808 if (list->items == NULL) {
809 xmlXPathErrMemory(NULL,
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800810 "xmlPointerListAddSize: re-allocating item\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000811 list->size = 0;
812 return(-1);
813 }
814 }
815 list->items[list->number++] = item;
816 return(0);
817}
818
819/**
820 * xsltPointerListCreate:
821 *
822 * Creates an xsltPointerList structure.
823 *
824 * Returns a xsltPointerList structure or NULL in case of an error.
825 */
826static xmlPointerListPtr
827xmlPointerListCreate(int initialSize)
828{
829 xmlPointerListPtr ret;
830
831 ret = xmlMalloc(sizeof(xmlPointerList));
832 if (ret == NULL) {
833 xmlXPathErrMemory(NULL,
834 "xmlPointerListCreate: allocating item\n");
835 return (NULL);
836 }
837 memset(ret, 0, sizeof(xmlPointerList));
838 if (initialSize > 0) {
839 xmlPointerListAddSize(ret, NULL, initialSize);
840 ret->number = 0;
841 }
842 return (ret);
843}
844
845/**
846 * xsltPointerListFree:
847 *
848 * Frees the xsltPointerList structure. This does not free
849 * the content of the list.
850 */
851static void
852xmlPointerListFree(xmlPointerListPtr list)
853{
854 if (list == NULL)
855 return;
856 if (list->items != NULL)
857 xmlFree(list->items);
858 xmlFree(list);
859}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000860
861/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000862 * *
863 * Parser Types *
864 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000865 ************************************************************************/
866
867/*
868 * Types are private:
869 */
870
871typedef enum {
872 XPATH_OP_END=0,
873 XPATH_OP_AND,
874 XPATH_OP_OR,
875 XPATH_OP_EQUAL,
876 XPATH_OP_CMP,
877 XPATH_OP_PLUS,
878 XPATH_OP_MULT,
879 XPATH_OP_UNION,
880 XPATH_OP_ROOT,
881 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000882 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000883 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000884 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000885 XPATH_OP_VARIABLE,
886 XPATH_OP_FUNCTION,
887 XPATH_OP_ARG,
888 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000889 XPATH_OP_FILTER, /* 17 */
890 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000891#ifdef LIBXML_XPTR_ENABLED
892 ,XPATH_OP_RANGETO
893#endif
894} xmlXPathOp;
895
896typedef enum {
897 AXIS_ANCESTOR = 1,
898 AXIS_ANCESTOR_OR_SELF,
899 AXIS_ATTRIBUTE,
900 AXIS_CHILD,
901 AXIS_DESCENDANT,
902 AXIS_DESCENDANT_OR_SELF,
903 AXIS_FOLLOWING,
904 AXIS_FOLLOWING_SIBLING,
905 AXIS_NAMESPACE,
906 AXIS_PARENT,
907 AXIS_PRECEDING,
908 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000909 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000910} xmlXPathAxisVal;
911
912typedef enum {
913 NODE_TEST_NONE = 0,
914 NODE_TEST_TYPE = 1,
915 NODE_TEST_PI = 2,
916 NODE_TEST_ALL = 3,
917 NODE_TEST_NS = 4,
918 NODE_TEST_NAME = 5
919} xmlXPathTestVal;
920
921typedef enum {
922 NODE_TYPE_NODE = 0,
923 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
924 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000925 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000926} xmlXPathTypeVal;
927
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000928typedef struct _xmlXPathStepOp xmlXPathStepOp;
929typedef xmlXPathStepOp *xmlXPathStepOpPtr;
930struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000931 xmlXPathOp op; /* The identifier of the operation */
932 int ch1; /* First child */
933 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000934 int value;
935 int value2;
936 int value3;
937 void *value4;
938 void *value5;
Nick Wellnhofer229d1f92016-08-22 13:21:57 +0200939 xmlXPathFunction cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000940 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000941};
942
943struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000944 int nbStep; /* Number of steps in this expression */
945 int maxStep; /* Maximum number of steps allocated */
946 xmlXPathStepOp *steps; /* ops for computation of this expression */
947 int last; /* index of last step in expression */
948 xmlChar *expr; /* the expression being computed */
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200949 xmlDictPtr dict; /* the dictionary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000950#ifdef DEBUG_EVAL_COUNTS
951 int nb;
952 xmlChar *string;
953#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000954#ifdef XPATH_STREAMING
955 xmlPatternPtr stream;
956#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000957};
958
959/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000960 * *
961 * Forward declarations *
962 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000963 ************************************************************************/
964static void
965xmlXPathFreeValueTree(xmlNodeSetPtr obj);
966static void
967xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
968static int
969xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
970 xmlXPathStepOpPtr op, xmlNodePtr *first);
971static int
972xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000973 xmlXPathStepOpPtr op,
974 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000975
976/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000977 * *
978 * Parser Type functions *
979 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000980 ************************************************************************/
981
982/**
983 * xmlXPathNewCompExpr:
984 *
985 * Create a new Xpath component
986 *
987 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
988 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000989static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000990xmlXPathNewCompExpr(void) {
991 xmlXPathCompExprPtr cur;
992
993 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
994 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000995 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000996 return(NULL);
997 }
998 memset(cur, 0, sizeof(xmlXPathCompExpr));
999 cur->maxStep = 10;
1000 cur->nbStep = 0;
1001 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1002 sizeof(xmlXPathStepOp));
1003 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001004 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001005 xmlFree(cur);
1006 return(NULL);
1007 }
1008 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1009 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +00001010#ifdef DEBUG_EVAL_COUNTS
1011 cur->nb = 0;
1012#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001013 return(cur);
1014}
1015
1016/**
1017 * xmlXPathFreeCompExpr:
1018 * @comp: an XPATH comp
1019 *
1020 * Free up the memory allocated by @comp
1021 */
1022void
Daniel Veillardf06307e2001-07-03 10:35:50 +00001023xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1024{
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001025 xmlXPathStepOpPtr op;
1026 int i;
1027
1028 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00001029 return;
Daniel Veillard4773df22004-01-23 13:15:13 +00001030 if (comp->dict == NULL) {
1031 for (i = 0; i < comp->nbStep; i++) {
1032 op = &comp->steps[i];
1033 if (op->value4 != NULL) {
1034 if (op->op == XPATH_OP_VALUE)
1035 xmlXPathFreeObject(op->value4);
1036 else
1037 xmlFree(op->value4);
1038 }
1039 if (op->value5 != NULL)
1040 xmlFree(op->value5);
1041 }
1042 } else {
1043 for (i = 0; i < comp->nbStep; i++) {
1044 op = &comp->steps[i];
1045 if (op->value4 != NULL) {
1046 if (op->op == XPATH_OP_VALUE)
1047 xmlXPathFreeObject(op->value4);
1048 }
1049 }
1050 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001051 }
1052 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00001053 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001054 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001055#ifdef DEBUG_EVAL_COUNTS
1056 if (comp->string != NULL) {
1057 xmlFree(comp->string);
1058 }
1059#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +00001060#ifdef XPATH_STREAMING
1061 if (comp->stream != NULL) {
1062 xmlFreePatternList(comp->stream);
1063 }
1064#endif
Daniel Veillard118aed72002-09-24 14:13:13 +00001065 if (comp->expr != NULL) {
1066 xmlFree(comp->expr);
1067 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001068
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001069 xmlFree(comp);
1070}
1071
1072/**
1073 * xmlXPathCompExprAdd:
1074 * @comp: the compiled expression
1075 * @ch1: first child index
1076 * @ch2: second child index
1077 * @op: an op
1078 * @value: the first int value
1079 * @value2: the second int value
1080 * @value3: the third int value
1081 * @value4: the first string value
1082 * @value5: the second string value
1083 *
William M. Brack08171912003-12-29 02:52:11 +00001084 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001085 *
1086 * Returns -1 in case of failure, the index otherwise
1087 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001088static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001089xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1090 xmlXPathOp op, int value,
1091 int value2, int value3, void *value4, void *value5) {
1092 if (comp->nbStep >= comp->maxStep) {
1093 xmlXPathStepOp *real;
1094
Daniel Veillardcd852ad2012-07-30 10:12:18 +08001095 if (comp->maxStep >= XPATH_MAX_STEPS) {
1096 xmlXPathErrMemory(NULL, "adding step\n");
1097 return(-1);
1098 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001099 comp->maxStep *= 2;
1100 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1101 comp->maxStep * sizeof(xmlXPathStepOp));
1102 if (real == NULL) {
1103 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001104 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001105 return(-1);
1106 }
1107 comp->steps = real;
1108 }
1109 comp->last = comp->nbStep;
1110 comp->steps[comp->nbStep].ch1 = ch1;
1111 comp->steps[comp->nbStep].ch2 = ch2;
1112 comp->steps[comp->nbStep].op = op;
1113 comp->steps[comp->nbStep].value = value;
1114 comp->steps[comp->nbStep].value2 = value2;
1115 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +00001116 if ((comp->dict != NULL) &&
1117 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1118 (op == XPATH_OP_COLLECT))) {
1119 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001120 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001121 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001122 xmlFree(value4);
1123 } else
1124 comp->steps[comp->nbStep].value4 = NULL;
1125 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001126 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001127 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001128 xmlFree(value5);
1129 } else
1130 comp->steps[comp->nbStep].value5 = NULL;
1131 } else {
1132 comp->steps[comp->nbStep].value4 = value4;
1133 comp->steps[comp->nbStep].value5 = value5;
1134 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00001135 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001136 return(comp->nbStep++);
1137}
1138
Daniel Veillardf06307e2001-07-03 10:35:50 +00001139/**
1140 * xmlXPathCompSwap:
1141 * @comp: the compiled expression
1142 * @op: operation index
1143 *
1144 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +00001145 */
1146static void
1147xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1148 int tmp;
1149
Daniel Veillardbc6f7592002-04-16 07:49:59 +00001150#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +00001151 /*
1152 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +00001153 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +00001154 * application
1155 */
1156 if (xmlXPathDisableOptimizer)
1157 return;
1158#endif
1159
Daniel Veillardf06307e2001-07-03 10:35:50 +00001160 tmp = op->ch1;
1161 op->ch1 = op->ch2;
1162 op->ch2 = tmp;
1163}
1164
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001165#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1166 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1167 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001168#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1169 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1170 (op), (val), (val2), (val3), (val4), (val5))
1171
Daniel Veillard45490ae2008-07-29 09:13:19 +00001172#define PUSH_LEAVE_EXPR(op, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001173xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1174
Daniel Veillard45490ae2008-07-29 09:13:19 +00001175#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001176xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1177
Daniel Veillard45490ae2008-07-29 09:13:19 +00001178#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +00001179xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1180 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001181
1182/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +00001183 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001184 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001185 * *
1186 ************************************************************************/
1187
1188/* #define XP_DEFAULT_CACHE_ON */
1189
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001190#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001191
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001192typedef struct _xmlXPathContextCache xmlXPathContextCache;
1193typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1194struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00001195 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1196 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1197 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1198 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1199 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001200 int maxNodeset;
1201 int maxString;
1202 int maxBoolean;
1203 int maxNumber;
1204 int maxMisc;
1205#ifdef XP_DEBUG_OBJ_USAGE
1206 int dbgCachedAll;
1207 int dbgCachedNodeset;
1208 int dbgCachedString;
1209 int dbgCachedBool;
1210 int dbgCachedNumber;
1211 int dbgCachedPoint;
1212 int dbgCachedRange;
1213 int dbgCachedLocset;
1214 int dbgCachedUsers;
1215 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001216 int dbgCachedUndefined;
1217
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001218
1219 int dbgReusedAll;
1220 int dbgReusedNodeset;
1221 int dbgReusedString;
1222 int dbgReusedBool;
1223 int dbgReusedNumber;
1224 int dbgReusedPoint;
1225 int dbgReusedRange;
1226 int dbgReusedLocset;
1227 int dbgReusedUsers;
1228 int dbgReusedXSLTTree;
1229 int dbgReusedUndefined;
1230
1231#endif
1232};
1233
1234/************************************************************************
1235 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001236 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +00001237 * *
1238 ************************************************************************/
1239
Daniel Veillard45490ae2008-07-29 09:13:19 +00001240#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +00001241 xmlGenericError(xmlGenericErrorContext, \
1242 "Internal error at %s:%d\n", \
1243 __FILE__, __LINE__);
1244
1245#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001246static void
1247xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001248 int i;
1249 char shift[100];
1250
1251 for (i = 0;((i < depth) && (i < 25));i++)
1252 shift[2 * i] = shift[2 * i + 1] = ' ';
1253 shift[2 * i] = shift[2 * i + 1] = 0;
1254 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001255 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001256 fprintf(output, "Node is NULL !\n");
1257 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001258
Owen Taylor3473f882001-02-23 17:55:21 +00001259 }
1260
1261 if ((cur->type == XML_DOCUMENT_NODE) ||
1262 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001263 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001264 fprintf(output, " /\n");
1265 } else if (cur->type == XML_ATTRIBUTE_NODE)
1266 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1267 else
1268 xmlDebugDumpOneNode(output, cur, depth);
1269}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001270static void
1271xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001272 xmlNodePtr tmp;
1273 int i;
1274 char shift[100];
1275
1276 for (i = 0;((i < depth) && (i < 25));i++)
1277 shift[2 * i] = shift[2 * i + 1] = ' ';
1278 shift[2 * i] = shift[2 * i + 1] = 0;
1279 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001280 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001281 fprintf(output, "Node is NULL !\n");
1282 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001283
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001284 }
1285
1286 while (cur != NULL) {
1287 tmp = cur;
1288 cur = cur->next;
1289 xmlDebugDumpOneNode(output, tmp, depth);
1290 }
1291}
Owen Taylor3473f882001-02-23 17:55:21 +00001292
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001293static void
1294xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001295 int i;
1296 char shift[100];
1297
1298 for (i = 0;((i < depth) && (i < 25));i++)
1299 shift[2 * i] = shift[2 * i + 1] = ' ';
1300 shift[2 * i] = shift[2 * i + 1] = 0;
1301
1302 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001303 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001304 fprintf(output, "NodeSet is NULL !\n");
1305 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001306
Owen Taylor3473f882001-02-23 17:55:21 +00001307 }
1308
Daniel Veillard911f49a2001-04-07 15:39:35 +00001309 if (cur != NULL) {
1310 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1311 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001312 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +00001313 fprintf(output, "%d", i + 1);
1314 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1315 }
Owen Taylor3473f882001-02-23 17:55:21 +00001316 }
1317}
1318
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001319static void
1320xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001321 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) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001329 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001330 fprintf(output, "Value Tree is NULL !\n");
1331 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001332
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001333 }
1334
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001335 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001336 fprintf(output, "%d", i + 1);
1337 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1338}
Owen Taylor3473f882001-02-23 17:55:21 +00001339#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001340static void
1341xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001342 int i;
1343 char shift[100];
1344
1345 for (i = 0;((i < depth) && (i < 25));i++)
1346 shift[2 * i] = shift[2 * i + 1] = ' ';
1347 shift[2 * i] = shift[2 * i + 1] = 0;
1348
1349 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001350 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001351 fprintf(output, "LocationSet is NULL !\n");
1352 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001353
Owen Taylor3473f882001-02-23 17:55:21 +00001354 }
1355
1356 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001357 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001358 fprintf(output, "%d : ", i + 1);
1359 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1360 }
1361}
Daniel Veillard017b1082001-06-21 11:20:21 +00001362#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001363
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00001364/**
1365 * xmlXPathDebugDumpObject:
1366 * @output: the FILE * to dump the output
1367 * @cur: the object to inspect
1368 * @depth: indentation level
1369 *
1370 * Dump the content of the object for debugging purposes
1371 */
1372void
1373xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001374 int i;
1375 char shift[100];
1376
Daniel Veillarda82b1822004-11-08 16:24:57 +00001377 if (output == NULL) return;
1378
Owen Taylor3473f882001-02-23 17:55:21 +00001379 for (i = 0;((i < depth) && (i < 25));i++)
1380 shift[2 * i] = shift[2 * i + 1] = ' ';
1381 shift[2 * i] = shift[2 * i + 1] = 0;
1382
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001383
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001384 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001385
1386 if (cur == NULL) {
1387 fprintf(output, "Object is empty (NULL)\n");
1388 return;
1389 }
1390 switch(cur->type) {
1391 case XPATH_UNDEFINED:
1392 fprintf(output, "Object is uninitialized\n");
1393 break;
1394 case XPATH_NODESET:
1395 fprintf(output, "Object is a Node Set :\n");
1396 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1397 break;
1398 case XPATH_XSLT_TREE:
1399 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001400 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001401 break;
1402 case XPATH_BOOLEAN:
1403 fprintf(output, "Object is a Boolean : ");
1404 if (cur->boolval) fprintf(output, "true\n");
1405 else fprintf(output, "false\n");
1406 break;
1407 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001408 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001409 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001410 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001411 break;
1412 case -1:
1413 fprintf(output, "Object is a number : -Infinity\n");
1414 break;
1415 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001416 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001417 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001418 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1419 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001420 } else {
1421 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1422 }
1423 }
Owen Taylor3473f882001-02-23 17:55:21 +00001424 break;
1425 case XPATH_STRING:
1426 fprintf(output, "Object is a string : ");
1427 xmlDebugDumpString(output, cur->stringval);
1428 fprintf(output, "\n");
1429 break;
1430 case XPATH_POINT:
1431 fprintf(output, "Object is a point : index %d in node", cur->index);
1432 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1433 fprintf(output, "\n");
1434 break;
1435 case XPATH_RANGE:
1436 if ((cur->user2 == NULL) ||
1437 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1438 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001439 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001440 if (cur->index >= 0)
1441 fprintf(output, "index %d in ", cur->index);
1442 fprintf(output, "node\n");
1443 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1444 depth + 1);
1445 } else {
1446 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001447 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001448 fprintf(output, "From ");
1449 if (cur->index >= 0)
1450 fprintf(output, "index %d in ", cur->index);
1451 fprintf(output, "node\n");
1452 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1453 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001454 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001455 fprintf(output, "To ");
1456 if (cur->index2 >= 0)
1457 fprintf(output, "index %d in ", cur->index2);
1458 fprintf(output, "node\n");
1459 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1460 depth + 1);
1461 fprintf(output, "\n");
1462 }
1463 break;
1464 case XPATH_LOCATIONSET:
1465#if defined(LIBXML_XPTR_ENABLED)
1466 fprintf(output, "Object is a Location Set:\n");
1467 xmlXPathDebugDumpLocationSet(output,
1468 (xmlLocationSetPtr) cur->user, depth);
1469#endif
1470 break;
1471 case XPATH_USERS:
1472 fprintf(output, "Object is user defined\n");
1473 break;
1474 }
1475}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001476
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001477static void
1478xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001479 xmlXPathStepOpPtr op, int depth) {
1480 int i;
1481 char shift[100];
1482
1483 for (i = 0;((i < depth) && (i < 25));i++)
1484 shift[2 * i] = shift[2 * i + 1] = ' ';
1485 shift[2 * i] = shift[2 * i + 1] = 0;
1486
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001487 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001488 if (op == NULL) {
1489 fprintf(output, "Step is NULL\n");
1490 return;
1491 }
1492 switch (op->op) {
1493 case XPATH_OP_END:
1494 fprintf(output, "END"); break;
1495 case XPATH_OP_AND:
1496 fprintf(output, "AND"); break;
1497 case XPATH_OP_OR:
1498 fprintf(output, "OR"); break;
1499 case XPATH_OP_EQUAL:
1500 if (op->value)
1501 fprintf(output, "EQUAL =");
1502 else
1503 fprintf(output, "EQUAL !=");
1504 break;
1505 case XPATH_OP_CMP:
1506 if (op->value)
1507 fprintf(output, "CMP <");
1508 else
1509 fprintf(output, "CMP >");
1510 if (!op->value2)
1511 fprintf(output, "=");
1512 break;
1513 case XPATH_OP_PLUS:
1514 if (op->value == 0)
1515 fprintf(output, "PLUS -");
1516 else if (op->value == 1)
1517 fprintf(output, "PLUS +");
1518 else if (op->value == 2)
1519 fprintf(output, "PLUS unary -");
1520 else if (op->value == 3)
1521 fprintf(output, "PLUS unary - -");
1522 break;
1523 case XPATH_OP_MULT:
1524 if (op->value == 0)
1525 fprintf(output, "MULT *");
1526 else if (op->value == 1)
1527 fprintf(output, "MULT div");
1528 else
1529 fprintf(output, "MULT mod");
1530 break;
1531 case XPATH_OP_UNION:
1532 fprintf(output, "UNION"); break;
1533 case XPATH_OP_ROOT:
1534 fprintf(output, "ROOT"); break;
1535 case XPATH_OP_NODE:
1536 fprintf(output, "NODE"); break;
1537 case XPATH_OP_RESET:
1538 fprintf(output, "RESET"); break;
1539 case XPATH_OP_SORT:
1540 fprintf(output, "SORT"); break;
1541 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001542 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1543 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1544 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001545 const xmlChar *prefix = op->value4;
1546 const xmlChar *name = op->value5;
1547
1548 fprintf(output, "COLLECT ");
1549 switch (axis) {
1550 case AXIS_ANCESTOR:
1551 fprintf(output, " 'ancestors' "); break;
1552 case AXIS_ANCESTOR_OR_SELF:
1553 fprintf(output, " 'ancestors-or-self' "); break;
1554 case AXIS_ATTRIBUTE:
1555 fprintf(output, " 'attributes' "); break;
1556 case AXIS_CHILD:
1557 fprintf(output, " 'child' "); break;
1558 case AXIS_DESCENDANT:
1559 fprintf(output, " 'descendant' "); break;
1560 case AXIS_DESCENDANT_OR_SELF:
1561 fprintf(output, " 'descendant-or-self' "); break;
1562 case AXIS_FOLLOWING:
1563 fprintf(output, " 'following' "); break;
1564 case AXIS_FOLLOWING_SIBLING:
1565 fprintf(output, " 'following-siblings' "); break;
1566 case AXIS_NAMESPACE:
1567 fprintf(output, " 'namespace' "); break;
1568 case AXIS_PARENT:
1569 fprintf(output, " 'parent' "); break;
1570 case AXIS_PRECEDING:
1571 fprintf(output, " 'preceding' "); break;
1572 case AXIS_PRECEDING_SIBLING:
1573 fprintf(output, " 'preceding-sibling' "); break;
1574 case AXIS_SELF:
1575 fprintf(output, " 'self' "); break;
1576 }
1577 switch (test) {
1578 case NODE_TEST_NONE:
1579 fprintf(output, "'none' "); break;
1580 case NODE_TEST_TYPE:
1581 fprintf(output, "'type' "); break;
1582 case NODE_TEST_PI:
1583 fprintf(output, "'PI' "); break;
1584 case NODE_TEST_ALL:
1585 fprintf(output, "'all' "); break;
1586 case NODE_TEST_NS:
1587 fprintf(output, "'namespace' "); break;
1588 case NODE_TEST_NAME:
1589 fprintf(output, "'name' "); break;
1590 }
1591 switch (type) {
1592 case NODE_TYPE_NODE:
1593 fprintf(output, "'node' "); break;
1594 case NODE_TYPE_COMMENT:
1595 fprintf(output, "'comment' "); break;
1596 case NODE_TYPE_TEXT:
1597 fprintf(output, "'text' "); break;
1598 case NODE_TYPE_PI:
1599 fprintf(output, "'PI' "); break;
1600 }
1601 if (prefix != NULL)
1602 fprintf(output, "%s:", prefix);
1603 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001604 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001605 break;
1606
1607 }
1608 case XPATH_OP_VALUE: {
1609 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1610
1611 fprintf(output, "ELEM ");
1612 xmlXPathDebugDumpObject(output, object, 0);
1613 goto finish;
1614 }
1615 case XPATH_OP_VARIABLE: {
1616 const xmlChar *prefix = op->value5;
1617 const xmlChar *name = op->value4;
1618
1619 if (prefix != NULL)
1620 fprintf(output, "VARIABLE %s:%s", prefix, name);
1621 else
1622 fprintf(output, "VARIABLE %s", name);
1623 break;
1624 }
1625 case XPATH_OP_FUNCTION: {
1626 int nbargs = op->value;
1627 const xmlChar *prefix = op->value5;
1628 const xmlChar *name = op->value4;
1629
1630 if (prefix != NULL)
1631 fprintf(output, "FUNCTION %s:%s(%d args)",
1632 prefix, name, nbargs);
1633 else
1634 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1635 break;
1636 }
1637 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1638 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001639 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001640#ifdef LIBXML_XPTR_ENABLED
1641 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1642#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001643 default:
1644 fprintf(output, "UNKNOWN %d\n", op->op); return;
1645 }
1646 fprintf(output, "\n");
1647finish:
1648 if (op->ch1 >= 0)
1649 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1650 if (op->ch2 >= 0)
1651 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1652}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001653
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001654/**
1655 * xmlXPathDebugDumpCompExpr:
1656 * @output: the FILE * for the output
1657 * @comp: the precompiled XPath expression
1658 * @depth: the indentation level.
1659 *
1660 * Dumps the tree of the compiled XPath expression.
1661 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001662void
1663xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1664 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001665 int i;
1666 char shift[100];
1667
Daniel Veillarda82b1822004-11-08 16:24:57 +00001668 if ((output == NULL) || (comp == NULL)) return;
1669
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001670 for (i = 0;((i < depth) && (i < 25));i++)
1671 shift[2 * i] = shift[2 * i + 1] = ' ';
1672 shift[2 * i] = shift[2 * i + 1] = 0;
1673
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001674 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001675
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001676 fprintf(output, "Compiled Expression : %d elements\n",
1677 comp->nbStep);
1678 i = comp->last;
1679 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1680}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001681
1682#ifdef XP_DEBUG_OBJ_USAGE
1683
1684/*
1685* XPath object usage related debugging variables.
1686*/
1687static int xmlXPathDebugObjCounterUndefined = 0;
1688static int xmlXPathDebugObjCounterNodeset = 0;
1689static int xmlXPathDebugObjCounterBool = 0;
1690static int xmlXPathDebugObjCounterNumber = 0;
1691static int xmlXPathDebugObjCounterString = 0;
1692static int xmlXPathDebugObjCounterPoint = 0;
1693static int xmlXPathDebugObjCounterRange = 0;
1694static int xmlXPathDebugObjCounterLocset = 0;
1695static int xmlXPathDebugObjCounterUsers = 0;
1696static int xmlXPathDebugObjCounterXSLTTree = 0;
1697static int xmlXPathDebugObjCounterAll = 0;
1698
1699static int xmlXPathDebugObjTotalUndefined = 0;
1700static int xmlXPathDebugObjTotalNodeset = 0;
1701static int xmlXPathDebugObjTotalBool = 0;
1702static int xmlXPathDebugObjTotalNumber = 0;
1703static int xmlXPathDebugObjTotalString = 0;
1704static int xmlXPathDebugObjTotalPoint = 0;
1705static int xmlXPathDebugObjTotalRange = 0;
1706static int xmlXPathDebugObjTotalLocset = 0;
1707static int xmlXPathDebugObjTotalUsers = 0;
1708static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001709static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001710
1711static int xmlXPathDebugObjMaxUndefined = 0;
1712static int xmlXPathDebugObjMaxNodeset = 0;
1713static int xmlXPathDebugObjMaxBool = 0;
1714static int xmlXPathDebugObjMaxNumber = 0;
1715static int xmlXPathDebugObjMaxString = 0;
1716static int xmlXPathDebugObjMaxPoint = 0;
1717static int xmlXPathDebugObjMaxRange = 0;
1718static int xmlXPathDebugObjMaxLocset = 0;
1719static int xmlXPathDebugObjMaxUsers = 0;
1720static int xmlXPathDebugObjMaxXSLTTree = 0;
1721static int xmlXPathDebugObjMaxAll = 0;
1722
1723/* REVISIT TODO: Make this static when committing */
1724static void
1725xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1726{
1727 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001728 if (ctxt->cache != NULL) {
1729 xmlXPathContextCachePtr cache =
1730 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001731
1732 cache->dbgCachedAll = 0;
1733 cache->dbgCachedNodeset = 0;
1734 cache->dbgCachedString = 0;
1735 cache->dbgCachedBool = 0;
1736 cache->dbgCachedNumber = 0;
1737 cache->dbgCachedPoint = 0;
1738 cache->dbgCachedRange = 0;
1739 cache->dbgCachedLocset = 0;
1740 cache->dbgCachedUsers = 0;
1741 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001742 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001743
1744 cache->dbgReusedAll = 0;
1745 cache->dbgReusedNodeset = 0;
1746 cache->dbgReusedString = 0;
1747 cache->dbgReusedBool = 0;
1748 cache->dbgReusedNumber = 0;
1749 cache->dbgReusedPoint = 0;
1750 cache->dbgReusedRange = 0;
1751 cache->dbgReusedLocset = 0;
1752 cache->dbgReusedUsers = 0;
1753 cache->dbgReusedXSLTTree = 0;
1754 cache->dbgReusedUndefined = 0;
1755 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001756 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001757
1758 xmlXPathDebugObjCounterUndefined = 0;
1759 xmlXPathDebugObjCounterNodeset = 0;
1760 xmlXPathDebugObjCounterBool = 0;
1761 xmlXPathDebugObjCounterNumber = 0;
1762 xmlXPathDebugObjCounterString = 0;
1763 xmlXPathDebugObjCounterPoint = 0;
1764 xmlXPathDebugObjCounterRange = 0;
1765 xmlXPathDebugObjCounterLocset = 0;
1766 xmlXPathDebugObjCounterUsers = 0;
1767 xmlXPathDebugObjCounterXSLTTree = 0;
1768 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001769
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001770 xmlXPathDebugObjTotalUndefined = 0;
1771 xmlXPathDebugObjTotalNodeset = 0;
1772 xmlXPathDebugObjTotalBool = 0;
1773 xmlXPathDebugObjTotalNumber = 0;
1774 xmlXPathDebugObjTotalString = 0;
1775 xmlXPathDebugObjTotalPoint = 0;
1776 xmlXPathDebugObjTotalRange = 0;
1777 xmlXPathDebugObjTotalLocset = 0;
1778 xmlXPathDebugObjTotalUsers = 0;
1779 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001780 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001781
1782 xmlXPathDebugObjMaxUndefined = 0;
1783 xmlXPathDebugObjMaxNodeset = 0;
1784 xmlXPathDebugObjMaxBool = 0;
1785 xmlXPathDebugObjMaxNumber = 0;
1786 xmlXPathDebugObjMaxString = 0;
1787 xmlXPathDebugObjMaxPoint = 0;
1788 xmlXPathDebugObjMaxRange = 0;
1789 xmlXPathDebugObjMaxLocset = 0;
1790 xmlXPathDebugObjMaxUsers = 0;
1791 xmlXPathDebugObjMaxXSLTTree = 0;
1792 xmlXPathDebugObjMaxAll = 0;
1793
1794}
1795
1796static void
1797xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1798 xmlXPathObjectType objType)
1799{
1800 int isCached = 0;
1801
1802 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001803 if (ctxt->cache != NULL) {
1804 xmlXPathContextCachePtr cache =
1805 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001806
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001807 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001808
1809 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001810 switch (objType) {
1811 case XPATH_UNDEFINED:
1812 cache->dbgReusedUndefined++;
1813 break;
1814 case XPATH_NODESET:
1815 cache->dbgReusedNodeset++;
1816 break;
1817 case XPATH_BOOLEAN:
1818 cache->dbgReusedBool++;
1819 break;
1820 case XPATH_NUMBER:
1821 cache->dbgReusedNumber++;
1822 break;
1823 case XPATH_STRING:
1824 cache->dbgReusedString++;
1825 break;
1826 case XPATH_POINT:
1827 cache->dbgReusedPoint++;
1828 break;
1829 case XPATH_RANGE:
1830 cache->dbgReusedRange++;
1831 break;
1832 case XPATH_LOCATIONSET:
1833 cache->dbgReusedLocset++;
1834 break;
1835 case XPATH_USERS:
1836 cache->dbgReusedUsers++;
1837 break;
1838 case XPATH_XSLT_TREE:
1839 cache->dbgReusedXSLTTree++;
1840 break;
1841 default:
1842 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001843 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001844 }
1845 }
1846
1847 switch (objType) {
1848 case XPATH_UNDEFINED:
1849 if (! isCached)
1850 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001851 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001852 if (xmlXPathDebugObjCounterUndefined >
1853 xmlXPathDebugObjMaxUndefined)
1854 xmlXPathDebugObjMaxUndefined =
1855 xmlXPathDebugObjCounterUndefined;
1856 break;
1857 case XPATH_NODESET:
1858 if (! isCached)
1859 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001860 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001861 if (xmlXPathDebugObjCounterNodeset >
1862 xmlXPathDebugObjMaxNodeset)
1863 xmlXPathDebugObjMaxNodeset =
1864 xmlXPathDebugObjCounterNodeset;
1865 break;
1866 case XPATH_BOOLEAN:
1867 if (! isCached)
1868 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001869 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001870 if (xmlXPathDebugObjCounterBool >
1871 xmlXPathDebugObjMaxBool)
1872 xmlXPathDebugObjMaxBool =
1873 xmlXPathDebugObjCounterBool;
1874 break;
1875 case XPATH_NUMBER:
1876 if (! isCached)
1877 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001878 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001879 if (xmlXPathDebugObjCounterNumber >
1880 xmlXPathDebugObjMaxNumber)
1881 xmlXPathDebugObjMaxNumber =
1882 xmlXPathDebugObjCounterNumber;
1883 break;
1884 case XPATH_STRING:
1885 if (! isCached)
1886 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001887 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001888 if (xmlXPathDebugObjCounterString >
1889 xmlXPathDebugObjMaxString)
1890 xmlXPathDebugObjMaxString =
1891 xmlXPathDebugObjCounterString;
1892 break;
1893 case XPATH_POINT:
1894 if (! isCached)
1895 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001896 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001897 if (xmlXPathDebugObjCounterPoint >
1898 xmlXPathDebugObjMaxPoint)
1899 xmlXPathDebugObjMaxPoint =
1900 xmlXPathDebugObjCounterPoint;
1901 break;
1902 case XPATH_RANGE:
1903 if (! isCached)
1904 xmlXPathDebugObjTotalRange++;
1905 xmlXPathDebugObjCounterRange++;
1906 if (xmlXPathDebugObjCounterRange >
1907 xmlXPathDebugObjMaxRange)
1908 xmlXPathDebugObjMaxRange =
1909 xmlXPathDebugObjCounterRange;
1910 break;
1911 case XPATH_LOCATIONSET:
1912 if (! isCached)
1913 xmlXPathDebugObjTotalLocset++;
1914 xmlXPathDebugObjCounterLocset++;
1915 if (xmlXPathDebugObjCounterLocset >
1916 xmlXPathDebugObjMaxLocset)
1917 xmlXPathDebugObjMaxLocset =
1918 xmlXPathDebugObjCounterLocset;
1919 break;
1920 case XPATH_USERS:
1921 if (! isCached)
1922 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001923 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001924 if (xmlXPathDebugObjCounterUsers >
1925 xmlXPathDebugObjMaxUsers)
1926 xmlXPathDebugObjMaxUsers =
1927 xmlXPathDebugObjCounterUsers;
1928 break;
1929 case XPATH_XSLT_TREE:
1930 if (! isCached)
1931 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001932 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001933 if (xmlXPathDebugObjCounterXSLTTree >
1934 xmlXPathDebugObjMaxXSLTTree)
1935 xmlXPathDebugObjMaxXSLTTree =
1936 xmlXPathDebugObjCounterXSLTTree;
1937 break;
1938 default:
1939 break;
1940 }
1941 if (! isCached)
1942 xmlXPathDebugObjTotalAll++;
1943 xmlXPathDebugObjCounterAll++;
1944 if (xmlXPathDebugObjCounterAll >
1945 xmlXPathDebugObjMaxAll)
1946 xmlXPathDebugObjMaxAll =
1947 xmlXPathDebugObjCounterAll;
1948}
1949
1950static void
1951xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1952 xmlXPathObjectType objType)
1953{
1954 int isCached = 0;
1955
1956 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001957 if (ctxt->cache != NULL) {
1958 xmlXPathContextCachePtr cache =
1959 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001960
Daniel Veillard45490ae2008-07-29 09:13:19 +00001961 isCached = 1;
1962
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001963 cache->dbgCachedAll++;
1964 switch (objType) {
1965 case XPATH_UNDEFINED:
1966 cache->dbgCachedUndefined++;
1967 break;
1968 case XPATH_NODESET:
1969 cache->dbgCachedNodeset++;
1970 break;
1971 case XPATH_BOOLEAN:
1972 cache->dbgCachedBool++;
1973 break;
1974 case XPATH_NUMBER:
1975 cache->dbgCachedNumber++;
1976 break;
1977 case XPATH_STRING:
1978 cache->dbgCachedString++;
1979 break;
1980 case XPATH_POINT:
1981 cache->dbgCachedPoint++;
1982 break;
1983 case XPATH_RANGE:
1984 cache->dbgCachedRange++;
1985 break;
1986 case XPATH_LOCATIONSET:
1987 cache->dbgCachedLocset++;
1988 break;
1989 case XPATH_USERS:
1990 cache->dbgCachedUsers++;
1991 break;
1992 case XPATH_XSLT_TREE:
1993 cache->dbgCachedXSLTTree++;
1994 break;
1995 default:
1996 break;
1997 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001998
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001999 }
2000 }
2001 switch (objType) {
2002 case XPATH_UNDEFINED:
2003 xmlXPathDebugObjCounterUndefined--;
2004 break;
2005 case XPATH_NODESET:
2006 xmlXPathDebugObjCounterNodeset--;
2007 break;
2008 case XPATH_BOOLEAN:
2009 xmlXPathDebugObjCounterBool--;
2010 break;
2011 case XPATH_NUMBER:
2012 xmlXPathDebugObjCounterNumber--;
2013 break;
2014 case XPATH_STRING:
2015 xmlXPathDebugObjCounterString--;
2016 break;
2017 case XPATH_POINT:
2018 xmlXPathDebugObjCounterPoint--;
2019 break;
2020 case XPATH_RANGE:
2021 xmlXPathDebugObjCounterRange--;
2022 break;
2023 case XPATH_LOCATIONSET:
2024 xmlXPathDebugObjCounterLocset--;
2025 break;
2026 case XPATH_USERS:
2027 xmlXPathDebugObjCounterUsers--;
2028 break;
2029 case XPATH_XSLT_TREE:
2030 xmlXPathDebugObjCounterXSLTTree--;
2031 break;
2032 default:
2033 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002034 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002035 xmlXPathDebugObjCounterAll--;
2036}
2037
2038/* REVISIT TODO: Make this static when committing */
2039static void
2040xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2041{
2042 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2043 reqXSLTTree, reqUndefined;
2044 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2045 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2046 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2047 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2048 int leftObjs = xmlXPathDebugObjCounterAll;
2049
2050 reqAll = xmlXPathDebugObjTotalAll;
2051 reqNodeset = xmlXPathDebugObjTotalNodeset;
2052 reqString = xmlXPathDebugObjTotalString;
2053 reqBool = xmlXPathDebugObjTotalBool;
2054 reqNumber = xmlXPathDebugObjTotalNumber;
2055 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2056 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002057
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002058 printf("# XPath object usage:\n");
2059
2060 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002061 if (ctxt->cache != NULL) {
2062 xmlXPathContextCachePtr cache =
2063 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002064
2065 reAll = cache->dbgReusedAll;
2066 reqAll += reAll;
2067 reNodeset = cache->dbgReusedNodeset;
2068 reqNodeset += reNodeset;
2069 reString = cache->dbgReusedString;
2070 reqString += reString;
2071 reBool = cache->dbgReusedBool;
2072 reqBool += reBool;
2073 reNumber = cache->dbgReusedNumber;
2074 reqNumber += reNumber;
2075 reXSLTTree = cache->dbgReusedXSLTTree;
2076 reqXSLTTree += reXSLTTree;
2077 reUndefined = cache->dbgReusedUndefined;
2078 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002079
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002080 caAll = cache->dbgCachedAll;
2081 caBool = cache->dbgCachedBool;
2082 caNodeset = cache->dbgCachedNodeset;
2083 caString = cache->dbgCachedString;
2084 caNumber = cache->dbgCachedNumber;
2085 caXSLTTree = cache->dbgCachedXSLTTree;
2086 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002087
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002088 if (cache->nodesetObjs)
2089 leftObjs -= cache->nodesetObjs->number;
2090 if (cache->stringObjs)
2091 leftObjs -= cache->stringObjs->number;
2092 if (cache->booleanObjs)
2093 leftObjs -= cache->booleanObjs->number;
2094 if (cache->numberObjs)
2095 leftObjs -= cache->numberObjs->number;
2096 if (cache->miscObjs)
2097 leftObjs -= cache->miscObjs->number;
2098 }
2099 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002100
2101 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002102 printf("# total : %d\n", reqAll);
2103 printf("# left : %d\n", leftObjs);
2104 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2105 printf("# reused : %d\n", reAll);
2106 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2107
2108 printf("# node-sets\n");
2109 printf("# total : %d\n", reqNodeset);
2110 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2111 printf("# reused : %d\n", reNodeset);
2112 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2113
2114 printf("# strings\n");
2115 printf("# total : %d\n", reqString);
2116 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2117 printf("# reused : %d\n", reString);
2118 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2119
2120 printf("# booleans\n");
2121 printf("# total : %d\n", reqBool);
2122 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2123 printf("# reused : %d\n", reBool);
2124 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2125
2126 printf("# numbers\n");
2127 printf("# total : %d\n", reqNumber);
2128 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2129 printf("# reused : %d\n", reNumber);
2130 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2131
2132 printf("# XSLT result tree fragments\n");
2133 printf("# total : %d\n", reqXSLTTree);
2134 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2135 printf("# reused : %d\n", reXSLTTree);
2136 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2137
2138 printf("# undefined\n");
2139 printf("# total : %d\n", reqUndefined);
2140 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2141 printf("# reused : %d\n", reUndefined);
2142 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2143
2144}
2145
2146#endif /* XP_DEBUG_OBJ_USAGE */
2147
Daniel Veillard017b1082001-06-21 11:20:21 +00002148#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002149
2150/************************************************************************
2151 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002152 * XPath object caching *
2153 * *
2154 ************************************************************************/
2155
2156/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002157 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002158 *
2159 * Create a new object cache
2160 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002161 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002162 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002163static xmlXPathContextCachePtr
2164xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002165{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002166 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002167
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002168 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002169 if (ret == NULL) {
2170 xmlXPathErrMemory(NULL, "creating object cache\n");
2171 return(NULL);
2172 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002173 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002174 ret->maxNodeset = 100;
2175 ret->maxString = 100;
2176 ret->maxBoolean = 100;
2177 ret->maxNumber = 100;
2178 ret->maxMisc = 100;
2179 return(ret);
2180}
2181
2182static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002183xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002184{
2185 int i;
2186 xmlXPathObjectPtr obj;
2187
2188 if (list == NULL)
2189 return;
2190
2191 for (i = 0; i < list->number; i++) {
2192 obj = list->items[i];
2193 /*
2194 * Note that it is already assured that we don't need to
2195 * look out for namespace nodes in the node-set.
2196 */
2197 if (obj->nodesetval != NULL) {
2198 if (obj->nodesetval->nodeTab != NULL)
2199 xmlFree(obj->nodesetval->nodeTab);
2200 xmlFree(obj->nodesetval);
2201 }
2202 xmlFree(obj);
2203#ifdef XP_DEBUG_OBJ_USAGE
2204 xmlXPathDebugObjCounterAll--;
2205#endif
2206 }
2207 xmlPointerListFree(list);
2208}
2209
2210static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002211xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002212{
2213 if (cache == NULL)
2214 return;
2215 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002216 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002217 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002218 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002219 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002220 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002221 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002222 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002223 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002224 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002225 xmlFree(cache);
2226}
2227
2228/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002229 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002230 *
2231 * @ctxt: the XPath context
2232 * @active: enables/disables (creates/frees) the cache
Daniel Veillard45490ae2008-07-29 09:13:19 +00002233 * @value: a value with semantics dependant on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002234 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002235 *
2236 * Creates/frees an object cache on the XPath context.
2237 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002238 * to be reused.
2239 * @options:
2240 * 0: This will set the XPath object caching:
2241 * @value:
2242 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002243 * to be cached per slot
2244 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002245 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002246 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002247 *
2248 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2249 */
2250int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002251xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2252 int active,
2253 int value,
2254 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002255{
2256 if (ctxt == NULL)
2257 return(-1);
2258 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002259 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002260
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002261 if (ctxt->cache == NULL) {
2262 ctxt->cache = xmlXPathNewCache();
2263 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002264 return(-1);
2265 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002266 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002267 if (options == 0) {
2268 if (value < 0)
2269 value = 100;
2270 cache->maxNodeset = value;
2271 cache->maxString = value;
2272 cache->maxNumber = value;
2273 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002274 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002275 }
2276 } else if (ctxt->cache != NULL) {
2277 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2278 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002279 }
2280 return(0);
2281}
2282
2283/**
2284 * xmlXPathCacheWrapNodeSet:
2285 * @ctxt: the XPath context
2286 * @val: the NodePtr value
2287 *
2288 * This is the cached version of xmlXPathWrapNodeSet().
2289 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2290 *
2291 * Returns the created or reused object.
2292 */
2293static xmlXPathObjectPtr
2294xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002295{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002296 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2297 xmlXPathContextCachePtr cache =
2298 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002299
2300 if ((cache->miscObjs != NULL) &&
2301 (cache->miscObjs->number != 0))
2302 {
2303 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002304
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002305 ret = (xmlXPathObjectPtr)
2306 cache->miscObjs->items[--cache->miscObjs->number];
2307 ret->type = XPATH_NODESET;
2308 ret->nodesetval = val;
2309#ifdef XP_DEBUG_OBJ_USAGE
2310 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2311#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00002312 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002313 }
2314 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002315
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002316 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00002317
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002318}
2319
2320/**
2321 * xmlXPathCacheWrapString:
2322 * @ctxt: the XPath context
2323 * @val: the xmlChar * value
2324 *
2325 * This is the cached version of xmlXPathWrapString().
2326 * Wraps the @val string into an XPath object.
2327 *
2328 * Returns the created or reused object.
2329 */
2330static xmlXPathObjectPtr
2331xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002332{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002333 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2334 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002335
2336 if ((cache->stringObjs != NULL) &&
2337 (cache->stringObjs->number != 0))
2338 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002339
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002340 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002341
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002342 ret = (xmlXPathObjectPtr)
2343 cache->stringObjs->items[--cache->stringObjs->number];
2344 ret->type = XPATH_STRING;
2345 ret->stringval = val;
2346#ifdef XP_DEBUG_OBJ_USAGE
2347 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2348#endif
2349 return(ret);
2350 } else if ((cache->miscObjs != NULL) &&
2351 (cache->miscObjs->number != 0))
2352 {
2353 xmlXPathObjectPtr ret;
2354 /*
2355 * Fallback to misc-cache.
2356 */
2357 ret = (xmlXPathObjectPtr)
2358 cache->miscObjs->items[--cache->miscObjs->number];
2359
2360 ret->type = XPATH_STRING;
2361 ret->stringval = val;
2362#ifdef XP_DEBUG_OBJ_USAGE
2363 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2364#endif
2365 return(ret);
2366 }
2367 }
2368 return(xmlXPathWrapString(val));
2369}
2370
2371/**
2372 * xmlXPathCacheNewNodeSet:
2373 * @ctxt: the XPath context
2374 * @val: the NodePtr value
2375 *
2376 * This is the cached version of xmlXPathNewNodeSet().
2377 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2378 * it with the single Node @val
2379 *
2380 * Returns the created or reused object.
2381 */
2382static xmlXPathObjectPtr
2383xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2384{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002385 if ((ctxt != NULL) && (ctxt->cache)) {
2386 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002387
2388 if ((cache->nodesetObjs != NULL) &&
2389 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002390 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002391 xmlXPathObjectPtr ret;
2392 /*
2393 * Use the nodset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002394 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002395 ret = (xmlXPathObjectPtr)
2396 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2397 ret->type = XPATH_NODESET;
2398 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002399 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002400 if ((ret->nodesetval->nodeMax == 0) ||
2401 (val->type == XML_NAMESPACE_DECL))
2402 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002403 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002404 } else {
2405 ret->nodesetval->nodeTab[0] = val;
2406 ret->nodesetval->nodeNr = 1;
2407 }
2408 }
2409#ifdef XP_DEBUG_OBJ_USAGE
2410 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2411#endif
2412 return(ret);
2413 } else if ((cache->miscObjs != NULL) &&
2414 (cache->miscObjs->number != 0))
2415 {
2416 xmlXPathObjectPtr ret;
2417 /*
2418 * Fallback to misc-cache.
2419 */
2420
2421 ret = (xmlXPathObjectPtr)
2422 cache->miscObjs->items[--cache->miscObjs->number];
2423
2424 ret->type = XPATH_NODESET;
2425 ret->boolval = 0;
2426 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08002427 if (ret->nodesetval == NULL) {
2428 ctxt->lastError.domain = XML_FROM_XPATH;
2429 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2430 return(NULL);
2431 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002432#ifdef XP_DEBUG_OBJ_USAGE
2433 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2434#endif
2435 return(ret);
2436 }
2437 }
2438 return(xmlXPathNewNodeSet(val));
2439}
2440
2441/**
2442 * xmlXPathCacheNewCString:
2443 * @ctxt: the XPath context
2444 * @val: the char * value
2445 *
2446 * This is the cached version of xmlXPathNewCString().
2447 * Acquire an xmlXPathObjectPtr of type string and of value @val
2448 *
2449 * Returns the created or reused object.
2450 */
2451static xmlXPathObjectPtr
2452xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002453{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002454 if ((ctxt != NULL) && (ctxt->cache)) {
2455 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002456
2457 if ((cache->stringObjs != NULL) &&
2458 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002459 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002460 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002461
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002462 ret = (xmlXPathObjectPtr)
2463 cache->stringObjs->items[--cache->stringObjs->number];
2464
2465 ret->type = XPATH_STRING;
2466 ret->stringval = xmlStrdup(BAD_CAST val);
2467#ifdef XP_DEBUG_OBJ_USAGE
2468 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2469#endif
2470 return(ret);
2471 } else if ((cache->miscObjs != NULL) &&
2472 (cache->miscObjs->number != 0))
2473 {
2474 xmlXPathObjectPtr ret;
2475
2476 ret = (xmlXPathObjectPtr)
2477 cache->miscObjs->items[--cache->miscObjs->number];
2478
2479 ret->type = XPATH_STRING;
2480 ret->stringval = xmlStrdup(BAD_CAST val);
2481#ifdef XP_DEBUG_OBJ_USAGE
2482 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2483#endif
2484 return(ret);
2485 }
2486 }
2487 return(xmlXPathNewCString(val));
2488}
2489
2490/**
2491 * xmlXPathCacheNewString:
2492 * @ctxt: the XPath context
2493 * @val: the xmlChar * value
2494 *
2495 * This is the cached version of xmlXPathNewString().
2496 * Acquire an xmlXPathObjectPtr of type string and of value @val
2497 *
2498 * Returns the created or reused object.
2499 */
2500static xmlXPathObjectPtr
2501xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002502{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002503 if ((ctxt != NULL) && (ctxt->cache)) {
2504 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002505
2506 if ((cache->stringObjs != NULL) &&
2507 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002508 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002509 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002510
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002511 ret = (xmlXPathObjectPtr)
2512 cache->stringObjs->items[--cache->stringObjs->number];
2513 ret->type = XPATH_STRING;
2514 if (val != NULL)
2515 ret->stringval = xmlStrdup(val);
2516 else
2517 ret->stringval = xmlStrdup((const xmlChar *)"");
2518#ifdef XP_DEBUG_OBJ_USAGE
2519 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2520#endif
2521 return(ret);
2522 } else if ((cache->miscObjs != NULL) &&
2523 (cache->miscObjs->number != 0))
2524 {
2525 xmlXPathObjectPtr ret;
2526
2527 ret = (xmlXPathObjectPtr)
2528 cache->miscObjs->items[--cache->miscObjs->number];
2529
2530 ret->type = XPATH_STRING;
2531 if (val != NULL)
2532 ret->stringval = xmlStrdup(val);
2533 else
2534 ret->stringval = xmlStrdup((const xmlChar *)"");
2535#ifdef XP_DEBUG_OBJ_USAGE
2536 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2537#endif
2538 return(ret);
2539 }
2540 }
2541 return(xmlXPathNewString(val));
2542}
2543
2544/**
2545 * xmlXPathCacheNewBoolean:
2546 * @ctxt: the XPath context
2547 * @val: the boolean value
2548 *
2549 * This is the cached version of xmlXPathNewBoolean().
2550 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2551 *
2552 * Returns the created or reused object.
2553 */
2554static xmlXPathObjectPtr
2555xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002556{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002557 if ((ctxt != NULL) && (ctxt->cache)) {
2558 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002559
2560 if ((cache->booleanObjs != NULL) &&
2561 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002562 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002563 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002564
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002565 ret = (xmlXPathObjectPtr)
2566 cache->booleanObjs->items[--cache->booleanObjs->number];
2567 ret->type = XPATH_BOOLEAN;
2568 ret->boolval = (val != 0);
2569#ifdef XP_DEBUG_OBJ_USAGE
2570 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2571#endif
2572 return(ret);
2573 } else if ((cache->miscObjs != NULL) &&
2574 (cache->miscObjs->number != 0))
2575 {
2576 xmlXPathObjectPtr ret;
2577
2578 ret = (xmlXPathObjectPtr)
2579 cache->miscObjs->items[--cache->miscObjs->number];
2580
2581 ret->type = XPATH_BOOLEAN;
2582 ret->boolval = (val != 0);
2583#ifdef XP_DEBUG_OBJ_USAGE
2584 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2585#endif
2586 return(ret);
2587 }
2588 }
2589 return(xmlXPathNewBoolean(val));
2590}
2591
2592/**
2593 * xmlXPathCacheNewFloat:
2594 * @ctxt: the XPath context
2595 * @val: the double value
2596 *
2597 * This is the cached version of xmlXPathNewFloat().
2598 * Acquires an xmlXPathObjectPtr of type double and of value @val
2599 *
2600 * Returns the created or reused object.
2601 */
2602static xmlXPathObjectPtr
2603xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2604{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002605 if ((ctxt != NULL) && (ctxt->cache)) {
2606 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002607
2608 if ((cache->numberObjs != NULL) &&
2609 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002610 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002611 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002612
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002613 ret = (xmlXPathObjectPtr)
2614 cache->numberObjs->items[--cache->numberObjs->number];
2615 ret->type = XPATH_NUMBER;
2616 ret->floatval = val;
2617#ifdef XP_DEBUG_OBJ_USAGE
2618 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2619#endif
2620 return(ret);
2621 } else if ((cache->miscObjs != NULL) &&
2622 (cache->miscObjs->number != 0))
2623 {
2624 xmlXPathObjectPtr ret;
2625
2626 ret = (xmlXPathObjectPtr)
2627 cache->miscObjs->items[--cache->miscObjs->number];
2628
2629 ret->type = XPATH_NUMBER;
2630 ret->floatval = val;
2631#ifdef XP_DEBUG_OBJ_USAGE
2632 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2633#endif
2634 return(ret);
2635 }
2636 }
2637 return(xmlXPathNewFloat(val));
2638}
2639
2640/**
2641 * xmlXPathCacheConvertString:
2642 * @ctxt: the XPath context
2643 * @val: an XPath object
2644 *
2645 * This is the cached version of xmlXPathConvertString().
2646 * Converts an existing object to its string() equivalent
2647 *
2648 * Returns a created or reused object, the old one is freed (cached)
2649 * (or the operation is done directly on @val)
2650 */
2651
2652static xmlXPathObjectPtr
2653xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002654 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002655
2656 if (val == NULL)
2657 return(xmlXPathCacheNewCString(ctxt, ""));
2658
2659 switch (val->type) {
2660 case XPATH_UNDEFINED:
2661#ifdef DEBUG_EXPR
2662 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2663#endif
2664 break;
2665 case XPATH_NODESET:
2666 case XPATH_XSLT_TREE:
2667 res = xmlXPathCastNodeSetToString(val->nodesetval);
2668 break;
2669 case XPATH_STRING:
2670 return(val);
2671 case XPATH_BOOLEAN:
2672 res = xmlXPathCastBooleanToString(val->boolval);
2673 break;
2674 case XPATH_NUMBER:
2675 res = xmlXPathCastNumberToString(val->floatval);
2676 break;
2677 case XPATH_USERS:
2678 case XPATH_POINT:
2679 case XPATH_RANGE:
2680 case XPATH_LOCATIONSET:
2681 TODO;
2682 break;
2683 }
2684 xmlXPathReleaseObject(ctxt, val);
2685 if (res == NULL)
2686 return(xmlXPathCacheNewCString(ctxt, ""));
2687 return(xmlXPathCacheWrapString(ctxt, res));
2688}
2689
2690/**
2691 * xmlXPathCacheObjectCopy:
2692 * @ctxt: the XPath context
2693 * @val: the original object
2694 *
2695 * This is the cached version of xmlXPathObjectCopy().
2696 * Acquire a copy of a given object
2697 *
2698 * Returns a created or reused created object.
2699 */
2700static xmlXPathObjectPtr
2701xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2702{
2703 if (val == NULL)
2704 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002705
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002706 if (XP_HAS_CACHE(ctxt)) {
2707 switch (val->type) {
2708 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002709 return(xmlXPathCacheWrapNodeSet(ctxt,
2710 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002711 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002712 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002713 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002714 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002715 case XPATH_NUMBER:
2716 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2717 default:
2718 break;
2719 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002720 }
2721 return(xmlXPathObjectCopy(val));
2722}
2723
2724/**
2725 * xmlXPathCacheConvertBoolean:
2726 * @ctxt: the XPath context
2727 * @val: an XPath object
2728 *
2729 * This is the cached version of xmlXPathConvertBoolean().
2730 * Converts an existing object to its boolean() equivalent
2731 *
2732 * Returns a created or reused object, the old one is freed (or the operation
2733 * is done directly on @val)
2734 */
2735static xmlXPathObjectPtr
2736xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2737 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002738
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002739 if (val == NULL)
2740 return(xmlXPathCacheNewBoolean(ctxt, 0));
2741 if (val->type == XPATH_BOOLEAN)
2742 return(val);
2743 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2744 xmlXPathReleaseObject(ctxt, val);
2745 return(ret);
2746}
2747
2748/**
2749 * xmlXPathCacheConvertNumber:
2750 * @ctxt: the XPath context
2751 * @val: an XPath object
2752 *
2753 * This is the cached version of xmlXPathConvertNumber().
2754 * Converts an existing object to its number() equivalent
2755 *
2756 * Returns a created or reused object, the old one is freed (or the operation
2757 * is done directly on @val)
2758 */
2759static xmlXPathObjectPtr
2760xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2761 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002762
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002763 if (val == NULL)
2764 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2765 if (val->type == XPATH_NUMBER)
2766 return(val);
2767 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2768 xmlXPathReleaseObject(ctxt, val);
2769 return(ret);
2770}
2771
2772/************************************************************************
2773 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002774 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002775 * *
2776 ************************************************************************/
2777
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002778/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002779 * xmlXPathSetFrame:
2780 * @ctxt: an XPath parser context
2781 *
2782 * Set the callee evaluation frame
2783 *
2784 * Returns the previous frame value to be restored once done
2785 */
2786static int
2787xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2788 int ret;
2789
2790 if (ctxt == NULL)
2791 return(0);
2792 ret = ctxt->valueFrame;
2793 ctxt->valueFrame = ctxt->valueNr;
2794 return(ret);
2795}
2796
2797/**
2798 * xmlXPathPopFrame:
2799 * @ctxt: an XPath parser context
2800 * @frame: the previous frame value
2801 *
2802 * Remove the callee evaluation frame
2803 */
2804static void
2805xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2806 if (ctxt == NULL)
2807 return;
2808 if (ctxt->valueNr < ctxt->valueFrame) {
2809 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2810 }
2811 ctxt->valueFrame = frame;
2812}
2813
2814/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002815 * valuePop:
2816 * @ctxt: an XPath evaluation context
2817 *
2818 * Pops the top XPath object from the value stack
2819 *
2820 * Returns the XPath object just removed
2821 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002822xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002823valuePop(xmlXPathParserContextPtr ctxt)
2824{
2825 xmlXPathObjectPtr ret;
2826
Daniel Veillarda82b1822004-11-08 16:24:57 +00002827 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002828 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002829
2830 if (ctxt->valueNr <= ctxt->valueFrame) {
2831 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2832 return (NULL);
2833 }
2834
Daniel Veillard1c732d22002-11-30 11:22:59 +00002835 ctxt->valueNr--;
2836 if (ctxt->valueNr > 0)
2837 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2838 else
2839 ctxt->value = NULL;
2840 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002841 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002842 return (ret);
2843}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002844/**
2845 * valuePush:
2846 * @ctxt: an XPath evaluation context
2847 * @value: the XPath object
2848 *
2849 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002850 *
2851 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002852 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002853int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002854valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2855{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002856 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002857 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002858 xmlXPathObjectPtr *tmp;
2859
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002860 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2861 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2862 ctxt->error = XPATH_MEMORY_ERROR;
2863 return (0);
2864 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002865 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2866 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002867 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002868 if (tmp == NULL) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002869 xmlXPathErrMemory(NULL, "pushing value\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08002870 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002871 return (0);
2872 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002873 ctxt->valueMax *= 2;
2874 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002875 }
2876 ctxt->valueTab[ctxt->valueNr] = value;
2877 ctxt->value = value;
2878 return (ctxt->valueNr++);
2879}
Owen Taylor3473f882001-02-23 17:55:21 +00002880
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002881/**
2882 * xmlXPathPopBoolean:
2883 * @ctxt: an XPath parser context
2884 *
2885 * Pops a boolean from the stack, handling conversion if needed.
2886 * Check error with #xmlXPathCheckError.
2887 *
2888 * Returns the boolean
2889 */
2890int
2891xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2892 xmlXPathObjectPtr obj;
2893 int ret;
2894
2895 obj = valuePop(ctxt);
2896 if (obj == NULL) {
2897 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2898 return(0);
2899 }
William M. Brack08171912003-12-29 02:52:11 +00002900 if (obj->type != XPATH_BOOLEAN)
2901 ret = xmlXPathCastToBoolean(obj);
2902 else
2903 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002904 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002905 return(ret);
2906}
2907
2908/**
2909 * xmlXPathPopNumber:
2910 * @ctxt: an XPath parser context
2911 *
2912 * Pops a number from the stack, handling conversion if needed.
2913 * Check error with #xmlXPathCheckError.
2914 *
2915 * Returns the number
2916 */
2917double
2918xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2919 xmlXPathObjectPtr obj;
2920 double ret;
2921
2922 obj = valuePop(ctxt);
2923 if (obj == NULL) {
2924 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2925 return(0);
2926 }
William M. Brack08171912003-12-29 02:52:11 +00002927 if (obj->type != XPATH_NUMBER)
2928 ret = xmlXPathCastToNumber(obj);
2929 else
2930 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002931 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002932 return(ret);
2933}
2934
2935/**
2936 * xmlXPathPopString:
2937 * @ctxt: an XPath parser context
2938 *
2939 * Pops a string from the stack, handling conversion if needed.
2940 * Check error with #xmlXPathCheckError.
2941 *
2942 * Returns the string
2943 */
2944xmlChar *
2945xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2946 xmlXPathObjectPtr obj;
2947 xmlChar * ret;
2948
2949 obj = valuePop(ctxt);
2950 if (obj == NULL) {
2951 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2952 return(NULL);
2953 }
William M. Brack08171912003-12-29 02:52:11 +00002954 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002955 /* TODO: needs refactoring somewhere else */
2956 if (obj->stringval == ret)
2957 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002958 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002959 return(ret);
2960}
2961
2962/**
2963 * xmlXPathPopNodeSet:
2964 * @ctxt: an XPath parser context
2965 *
2966 * Pops a node-set from the stack, handling conversion if needed.
2967 * Check error with #xmlXPathCheckError.
2968 *
2969 * Returns the node-set
2970 */
2971xmlNodeSetPtr
2972xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2973 xmlXPathObjectPtr obj;
2974 xmlNodeSetPtr ret;
2975
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002976 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002977 if (ctxt->value == NULL) {
2978 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2979 return(NULL);
2980 }
2981 if (!xmlXPathStackIsNodeSet(ctxt)) {
2982 xmlXPathSetTypeError(ctxt);
2983 return(NULL);
2984 }
2985 obj = valuePop(ctxt);
2986 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002987#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002988 /* to fix memory leak of not clearing obj->user */
2989 if (obj->boolval && obj->user != NULL)
2990 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002991#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002992 obj->nodesetval = NULL;
2993 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002994 return(ret);
2995}
2996
2997/**
2998 * xmlXPathPopExternal:
2999 * @ctxt: an XPath parser context
3000 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003001 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003002 * Check error with #xmlXPathCheckError.
3003 *
3004 * Returns the object
3005 */
3006void *
3007xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3008 xmlXPathObjectPtr obj;
3009 void * ret;
3010
Daniel Veillarda82b1822004-11-08 16:24:57 +00003011 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003012 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3013 return(NULL);
3014 }
3015 if (ctxt->value->type != XPATH_USERS) {
3016 xmlXPathSetTypeError(ctxt);
3017 return(NULL);
3018 }
3019 obj = valuePop(ctxt);
3020 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003021 obj->user = NULL;
3022 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003023 return(ret);
3024}
3025
Owen Taylor3473f882001-02-23 17:55:21 +00003026/*
3027 * Macros for accessing the content. Those should be used only by the parser,
3028 * and not exported.
3029 *
3030 * Dirty macros, i.e. one need to make assumption on the context to use them
3031 *
3032 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3033 * CUR returns the current xmlChar value, i.e. a 8 bit value
3034 * in ISO-Latin or UTF-8.
3035 * This should be used internally by the parser
3036 * only to compare to ASCII values otherwise it would break when
3037 * running with UTF-8 encoding.
3038 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3039 * to compare on ASCII based substring.
3040 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3041 * strings within the parser.
3042 * CURRENT Returns the current char value, with the full decoding of
3043 * UTF-8 if we are using this mode. It returns an int.
3044 * NEXT Skip to the next character, this does the proper decoding
3045 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3046 * It returns the pointer to the current xmlChar.
3047 */
3048
3049#define CUR (*ctxt->cur)
3050#define SKIP(val) ctxt->cur += (val)
3051#define NXT(val) ctxt->cur[(val)]
3052#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00003053#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3054
3055#define COPY_BUF(l,b,i,v) \
3056 if (l == 1) b[i++] = (xmlChar) v; \
3057 else i += xmlCopyChar(l,&b[i],v)
3058
3059#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00003060
Daniel Veillard45490ae2008-07-29 09:13:19 +00003061#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00003062 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00003063
3064#define CURRENT (*ctxt->cur)
3065#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3066
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003067
3068#ifndef DBL_DIG
3069#define DBL_DIG 16
3070#endif
3071#ifndef DBL_EPSILON
3072#define DBL_EPSILON 1E-9
3073#endif
3074
3075#define UPPER_DOUBLE 1E9
3076#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00003077#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003078
3079#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00003080#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003081#define EXPONENT_DIGITS (3 + 2)
3082
3083/**
3084 * xmlXPathFormatNumber:
3085 * @number: number to format
3086 * @buffer: output buffer
3087 * @buffersize: size of output buffer
3088 *
3089 * Convert the number into a string representation.
3090 */
3091static void
3092xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3093{
Daniel Veillardcda96922001-08-21 10:56:31 +00003094 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003095 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003096 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003097 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003098 break;
3099 case -1:
3100 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003101 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003102 break;
3103 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003104 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003105 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003106 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003107 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003108 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003109 } else if (number == ((int) number)) {
3110 char work[30];
3111 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00003112 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003113
3114 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003115 if (value == 0) {
3116 *ptr++ = '0';
3117 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00003118 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003119 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00003120 while ((*cur) && (ptr - buffer < buffersize)) {
3121 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003122 }
3123 }
3124 if (ptr - buffer < buffersize) {
3125 *ptr = 0;
3126 } else if (buffersize > 0) {
3127 ptr--;
3128 *ptr = 0;
3129 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003130 } else {
William M. Brackca797882007-05-11 14:45:53 +00003131 /*
3132 For the dimension of work,
3133 DBL_DIG is number of significant digits
3134 EXPONENT is only needed for "scientific notation"
3135 3 is sign, decimal point, and terminating zero
3136 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3137 Note that this dimension is slightly (a few characters)
3138 larger than actually necessary.
3139 */
3140 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003141 int integer_place, fraction_place;
3142 char *ptr;
3143 char *after_fraction;
3144 double absolute_value;
3145 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003146
Bjorn Reese70a9da52001-04-21 16:57:29 +00003147 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003148
Bjorn Reese70a9da52001-04-21 16:57:29 +00003149 /*
3150 * First choose format - scientific or regular floating point.
3151 * In either case, result is in work, and after_fraction points
3152 * just past the fractional part.
3153 */
3154 if ( ((absolute_value > UPPER_DOUBLE) ||
3155 (absolute_value < LOWER_DOUBLE)) &&
3156 (absolute_value != 0.0) ) {
3157 /* Use scientific notation */
3158 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3159 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003160 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00003161 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00003162 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003163
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003164 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003165 else {
3166 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00003167 if (absolute_value > 0.0) {
3168 integer_place = (int)log10(absolute_value);
3169 if (integer_place > 0)
3170 fraction_place = DBL_DIG - integer_place - 1;
3171 else
3172 fraction_place = DBL_DIG - integer_place;
3173 } else {
3174 fraction_place = 1;
3175 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003176 size = snprintf(work, sizeof(work), "%0.*f",
3177 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003178 }
3179
Daniel Veillardb9e4d5b2013-07-22 13:21:31 +08003180 /* Remove leading spaces sometimes inserted by snprintf */
3181 while (work[0] == ' ') {
3182 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3183 size--;
3184 }
3185
Bjorn Reese70a9da52001-04-21 16:57:29 +00003186 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00003187 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003188 ptr = after_fraction;
3189 while (*(--ptr) == '0')
3190 ;
3191 if (*ptr != '.')
3192 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003193 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003194
3195 /* Finally copy result back to caller */
3196 size = strlen(work) + 1;
3197 if (size > buffersize) {
3198 work[buffersize - 1] = 0;
3199 size = buffersize;
3200 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003201 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003202 }
3203 break;
3204 }
3205}
3206
Owen Taylor3473f882001-02-23 17:55:21 +00003207
3208/************************************************************************
3209 * *
3210 * Routines to handle NodeSets *
3211 * *
3212 ************************************************************************/
3213
3214/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003215 * xmlXPathOrderDocElems:
3216 * @doc: an input document
3217 *
3218 * Call this routine to speed up XPath computation on static documents.
3219 * This stamps all the element nodes with the document order
3220 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00003221 * field, the value stored is actually - the node number (starting at -1)
3222 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003223 *
William M. Brack08171912003-12-29 02:52:11 +00003224 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003225 * of error.
3226 */
3227long
3228xmlXPathOrderDocElems(xmlDocPtr doc) {
3229 long count = 0;
3230 xmlNodePtr cur;
3231
3232 if (doc == NULL)
3233 return(-1);
3234 cur = doc->children;
3235 while (cur != NULL) {
3236 if (cur->type == XML_ELEMENT_NODE) {
3237 cur->content = (void *) (-(++count));
3238 if (cur->children != NULL) {
3239 cur = cur->children;
3240 continue;
3241 }
3242 }
3243 if (cur->next != NULL) {
3244 cur = cur->next;
3245 continue;
3246 }
3247 do {
3248 cur = cur->parent;
3249 if (cur == NULL)
3250 break;
3251 if (cur == (xmlNodePtr) doc) {
3252 cur = NULL;
3253 break;
3254 }
3255 if (cur->next != NULL) {
3256 cur = cur->next;
3257 break;
3258 }
3259 } while (cur != NULL);
3260 }
3261 return(count);
3262}
3263
3264/**
Owen Taylor3473f882001-02-23 17:55:21 +00003265 * xmlXPathCmpNodes:
3266 * @node1: the first node
3267 * @node2: the second node
3268 *
3269 * Compare two nodes w.r.t document order
3270 *
3271 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00003272 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003273 */
3274int
3275xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3276 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003277 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003278 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003279 xmlNodePtr cur, root;
3280
3281 if ((node1 == NULL) || (node2 == NULL))
3282 return(-2);
3283 /*
3284 * a couple of optimizations which will avoid computations in most cases
3285 */
William M. Brackee0b9822007-03-07 08:15:01 +00003286 if (node1 == node2) /* trivial case */
3287 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00003288 if (node1->type == XML_ATTRIBUTE_NODE) {
3289 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003290 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003291 node1 = node1->parent;
3292 }
3293 if (node2->type == XML_ATTRIBUTE_NODE) {
3294 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003295 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003296 node2 = node2->parent;
3297 }
3298 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00003299 if (attr1 == attr2) {
3300 /* not required, but we keep attributes in order */
3301 if (attr1 != 0) {
3302 cur = attrNode2->prev;
3303 while (cur != NULL) {
3304 if (cur == attrNode1)
3305 return (1);
3306 cur = cur->prev;
3307 }
3308 return (-1);
3309 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003310 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00003311 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003312 if (attr2 == 1)
3313 return(1);
3314 return(-1);
3315 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003316 if ((node1->type == XML_NAMESPACE_DECL) ||
3317 (node2->type == XML_NAMESPACE_DECL))
3318 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003319 if (node1 == node2->prev)
3320 return(1);
3321 if (node1 == node2->next)
3322 return(-1);
3323
3324 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003325 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003326 */
3327 if ((node1->type == XML_ELEMENT_NODE) &&
3328 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003329 (0 > (long) node1->content) &&
3330 (0 > (long) node2->content) &&
3331 (node1->doc == node2->doc)) {
3332 long l1, l2;
3333
3334 l1 = -((long) node1->content);
3335 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003336 if (l1 < l2)
3337 return(1);
3338 if (l1 > l2)
3339 return(-1);
3340 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003341
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003342 /*
Owen Taylor3473f882001-02-23 17:55:21 +00003343 * compute depth to root
3344 */
3345 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003346 if (cur->parent == node1)
Owen Taylor3473f882001-02-23 17:55:21 +00003347 return(1);
3348 depth2++;
3349 }
3350 root = cur;
3351 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003352 if (cur->parent == node2)
Owen Taylor3473f882001-02-23 17:55:21 +00003353 return(-1);
3354 depth1++;
3355 }
3356 /*
3357 * Distinct document (or distinct entities :-( ) case.
3358 */
3359 if (root != cur) {
3360 return(-2);
3361 }
3362 /*
3363 * get the nearest common ancestor.
3364 */
3365 while (depth1 > depth2) {
3366 depth1--;
3367 node1 = node1->parent;
3368 }
3369 while (depth2 > depth1) {
3370 depth2--;
3371 node2 = node2->parent;
3372 }
3373 while (node1->parent != node2->parent) {
3374 node1 = node1->parent;
3375 node2 = node2->parent;
3376 /* should not happen but just in case ... */
3377 if ((node1 == NULL) || (node2 == NULL))
3378 return(-2);
3379 }
3380 /*
3381 * Find who's first.
3382 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003383 if (node1 == node2->prev)
3384 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003385 if (node1 == node2->next)
3386 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003387 /*
3388 * Speedup using document order if availble.
3389 */
3390 if ((node1->type == XML_ELEMENT_NODE) &&
3391 (node2->type == XML_ELEMENT_NODE) &&
3392 (0 > (long) node1->content) &&
3393 (0 > (long) node2->content) &&
3394 (node1->doc == node2->doc)) {
3395 long l1, l2;
3396
3397 l1 = -((long) node1->content);
3398 l2 = -((long) node2->content);
3399 if (l1 < l2)
3400 return(1);
3401 if (l1 > l2)
3402 return(-1);
3403 }
3404
Owen Taylor3473f882001-02-23 17:55:21 +00003405 for (cur = node1->next;cur != NULL;cur = cur->next)
3406 if (cur == node2)
3407 return(1);
3408 return(-1); /* assume there is no sibling list corruption */
3409}
3410
3411/**
3412 * xmlXPathNodeSetSort:
3413 * @set: the node set
3414 *
3415 * Sort the node set in document order
3416 */
3417void
3418xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Vojtech Fried3e031b72012-08-24 16:52:44 +08003419#ifndef WITH_TIM_SORT
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003420 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003421 xmlNodePtr tmp;
Vojtech Fried3e031b72012-08-24 16:52:44 +08003422#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003423
3424 if (set == NULL)
3425 return;
3426
Vojtech Fried3e031b72012-08-24 16:52:44 +08003427#ifndef WITH_TIM_SORT
3428 /*
3429 * Use the old Shell's sort implementation to sort the node-set
3430 * Timsort ought to be quite faster
3431 */
Owen Taylor3473f882001-02-23 17:55:21 +00003432 len = set->nodeNr;
3433 for (incr = len / 2; incr > 0; incr /= 2) {
3434 for (i = incr; i < len; i++) {
3435 j = i - incr;
3436 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003437#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003438 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3439 set->nodeTab[j + incr]) == -1)
3440#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003441 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003442 set->nodeTab[j + incr]) == -1)
3443#endif
3444 {
Owen Taylor3473f882001-02-23 17:55:21 +00003445 tmp = set->nodeTab[j];
3446 set->nodeTab[j] = set->nodeTab[j + incr];
3447 set->nodeTab[j + incr] = tmp;
3448 j -= incr;
3449 } else
3450 break;
3451 }
3452 }
3453 }
Vojtech Fried3e031b72012-08-24 16:52:44 +08003454#else /* WITH_TIM_SORT */
3455 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3456#endif /* WITH_TIM_SORT */
Owen Taylor3473f882001-02-23 17:55:21 +00003457}
3458
3459#define XML_NODESET_DEFAULT 10
3460/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003461 * xmlXPathNodeSetDupNs:
3462 * @node: the parent node of the namespace XPath node
3463 * @ns: the libxml namespace declaration node.
3464 *
3465 * Namespace node in libxml don't match the XPath semantic. In a node set
3466 * the namespace nodes are duplicated and the next pointer is set to the
3467 * parent node in the XPath semantic.
3468 *
3469 * Returns the newly created object.
3470 */
3471static xmlNodePtr
3472xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3473 xmlNsPtr cur;
3474
3475 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3476 return(NULL);
3477 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3478 return((xmlNodePtr) ns);
3479
3480 /*
3481 * Allocate a new Namespace and fill the fields.
3482 */
3483 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3484 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003485 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003486 return(NULL);
3487 }
3488 memset(cur, 0, sizeof(xmlNs));
3489 cur->type = XML_NAMESPACE_DECL;
3490 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003491 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003492 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003493 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003494 cur->next = (xmlNsPtr) node;
3495 return((xmlNodePtr) cur);
3496}
3497
3498/**
3499 * xmlXPathNodeSetFreeNs:
3500 * @ns: the XPath namespace node found in a nodeset.
3501 *
William M. Brack08171912003-12-29 02:52:11 +00003502 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003503 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003504 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003505 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003506void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003507xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3508 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3509 return;
3510
3511 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3512 if (ns->href != NULL)
3513 xmlFree((xmlChar *)ns->href);
3514 if (ns->prefix != NULL)
3515 xmlFree((xmlChar *)ns->prefix);
3516 xmlFree(ns);
3517 }
3518}
3519
3520/**
Owen Taylor3473f882001-02-23 17:55:21 +00003521 * xmlXPathNodeSetCreate:
3522 * @val: an initial xmlNodePtr, or NULL
3523 *
3524 * Create a new xmlNodeSetPtr of type double and of value @val
3525 *
3526 * Returns the newly created object.
3527 */
3528xmlNodeSetPtr
3529xmlXPathNodeSetCreate(xmlNodePtr val) {
3530 xmlNodeSetPtr ret;
3531
3532 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3533 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003534 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003535 return(NULL);
3536 }
3537 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3538 if (val != NULL) {
3539 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3540 sizeof(xmlNodePtr));
3541 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003542 xmlXPathErrMemory(NULL, "creating nodeset\n");
3543 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003544 return(NULL);
3545 }
3546 memset(ret->nodeTab, 0 ,
3547 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3548 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003549 if (val->type == XML_NAMESPACE_DECL) {
3550 xmlNsPtr ns = (xmlNsPtr) val;
3551
3552 ret->nodeTab[ret->nodeNr++] =
3553 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3554 } else
3555 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003556 }
3557 return(ret);
3558}
3559
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003560/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003561 * xmlXPathNodeSetCreateSize:
3562 * @size: the initial size of the set
3563 *
3564 * Create a new xmlNodeSetPtr of type double and of value @val
3565 *
3566 * Returns the newly created object.
3567 */
3568static xmlNodeSetPtr
3569xmlXPathNodeSetCreateSize(int size) {
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 (size < XML_NODESET_DEFAULT)
3579 size = XML_NODESET_DEFAULT;
3580 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * 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 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003587 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003588 return(ret);
3589}
3590
3591/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003592 * xmlXPathNodeSetContains:
3593 * @cur: the node-set
3594 * @val: the node
3595 *
3596 * checks whether @cur contains @val
3597 *
3598 * Returns true (1) if @cur contains @val, false (0) otherwise
3599 */
3600int
3601xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3602 int i;
3603
Daniel Veillarda82b1822004-11-08 16:24:57 +00003604 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003605 if (val->type == XML_NAMESPACE_DECL) {
3606 for (i = 0; i < cur->nodeNr; i++) {
3607 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3608 xmlNsPtr ns1, ns2;
3609
3610 ns1 = (xmlNsPtr) val;
3611 ns2 = (xmlNsPtr) cur->nodeTab[i];
3612 if (ns1 == ns2)
3613 return(1);
3614 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3615 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3616 return(1);
3617 }
3618 }
3619 } else {
3620 for (i = 0; i < cur->nodeNr; i++) {
3621 if (cur->nodeTab[i] == val)
3622 return(1);
3623 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003624 }
3625 return(0);
3626}
3627
3628/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003629 * xmlXPathNodeSetAddNs:
3630 * @cur: the initial node set
3631 * @node: the hosting node
3632 * @ns: a the namespace node
3633 *
3634 * add a new namespace node to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003635 *
3636 * Returns 0 in case of success and -1 in case of error
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003637 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003638int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003639xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3640 int i;
3641
Daniel Veillard45490ae2008-07-29 09:13:19 +00003642
Daniel Veillarda82b1822004-11-08 16:24:57 +00003643 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3644 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003645 (node->type != XML_ELEMENT_NODE))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003646 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003647
William M. Brack08171912003-12-29 02:52:11 +00003648 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003649 /*
William M. Brack08171912003-12-29 02:52:11 +00003650 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003651 */
3652 for (i = 0;i < cur->nodeNr;i++) {
3653 if ((cur->nodeTab[i] != NULL) &&
3654 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003655 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003656 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003657 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003658 }
3659
3660 /*
3661 * grow the nodeTab if needed
3662 */
3663 if (cur->nodeMax == 0) {
3664 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3665 sizeof(xmlNodePtr));
3666 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003667 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003668 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003669 }
3670 memset(cur->nodeTab, 0 ,
3671 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3672 cur->nodeMax = XML_NODESET_DEFAULT;
3673 } else if (cur->nodeNr == cur->nodeMax) {
3674 xmlNodePtr *temp;
3675
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003676 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3677 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003678 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003679 }
Chris Evansd7958b22011-03-23 08:13:06 +08003680 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003681 sizeof(xmlNodePtr));
3682 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003683 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003684 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003685 }
Chris Evansd7958b22011-03-23 08:13:06 +08003686 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003687 cur->nodeTab = temp;
3688 }
3689 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003690 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003691}
3692
3693/**
Owen Taylor3473f882001-02-23 17:55:21 +00003694 * xmlXPathNodeSetAdd:
3695 * @cur: the initial node set
3696 * @val: a new xmlNodePtr
3697 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003698 * add a new xmlNodePtr to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003699 *
3700 * Returns 0 in case of success, and -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00003701 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003702int
Owen Taylor3473f882001-02-23 17:55:21 +00003703xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3704 int i;
3705
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003706 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003707
William M. Brack08171912003-12-29 02:52:11 +00003708 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003709 /*
Shlomi Fishd5bd2a92016-04-03 05:14:44 +03003710 * prevent duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003711 */
3712 for (i = 0;i < cur->nodeNr;i++)
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003713 if (cur->nodeTab[i] == val) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003714
3715 /*
3716 * grow the nodeTab if needed
3717 */
3718 if (cur->nodeMax == 0) {
3719 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3720 sizeof(xmlNodePtr));
3721 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003722 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003723 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003724 }
3725 memset(cur->nodeTab, 0 ,
3726 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3727 cur->nodeMax = XML_NODESET_DEFAULT;
3728 } else if (cur->nodeNr == cur->nodeMax) {
3729 xmlNodePtr *temp;
3730
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003731 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3732 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003733 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003734 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003735 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003736 sizeof(xmlNodePtr));
3737 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003738 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003739 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003740 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003741 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003742 cur->nodeTab = temp;
3743 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003744 if (val->type == XML_NAMESPACE_DECL) {
3745 xmlNsPtr ns = (xmlNsPtr) val;
3746
Daniel Veillard45490ae2008-07-29 09:13:19 +00003747 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003748 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3749 } else
3750 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003751 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003752}
3753
3754/**
3755 * xmlXPathNodeSetAddUnique:
3756 * @cur: the initial node set
3757 * @val: a new xmlNodePtr
3758 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003759 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003760 * when we are sure the node is not already in the set.
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003761 *
3762 * Returns 0 in case of success and -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00003763 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003764int
Owen Taylor3473f882001-02-23 17:55:21 +00003765xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003766 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003767
William M. Brack08171912003-12-29 02:52:11 +00003768 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003769 /*
3770 * grow the nodeTab if needed
3771 */
3772 if (cur->nodeMax == 0) {
3773 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774 sizeof(xmlNodePtr));
3775 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003776 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003777 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003778 }
3779 memset(cur->nodeTab, 0 ,
3780 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781 cur->nodeMax = XML_NODESET_DEFAULT;
3782 } else if (cur->nodeNr == cur->nodeMax) {
3783 xmlNodePtr *temp;
3784
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003785 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3786 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003787 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003788 }
Chris Evansd7958b22011-03-23 08:13:06 +08003789 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003790 sizeof(xmlNodePtr));
3791 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003792 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003793 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003794 }
3795 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003796 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003797 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003798 if (val->type == XML_NAMESPACE_DECL) {
3799 xmlNsPtr ns = (xmlNsPtr) val;
3800
Daniel Veillard45490ae2008-07-29 09:13:19 +00003801 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003802 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3803 } else
3804 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003805 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003806}
3807
3808/**
3809 * xmlXPathNodeSetMerge:
3810 * @val1: the first NodeSet or NULL
3811 * @val2: the second NodeSet
3812 *
3813 * Merges two nodesets, all nodes from @val2 are added to @val1
3814 * if @val1 is NULL, a new set is created and copied from @val2
3815 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003816 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003817 */
3818xmlNodeSetPtr
3819xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003820 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003821 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003822
3823 if (val2 == NULL) return(val1);
3824 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003825 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003826 if (val1 == NULL)
3827 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003828#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003829 /*
3830 * TODO: The optimization won't work in every case, since
3831 * those nasty namespace nodes need to be added with
3832 * xmlXPathNodeSetDupNs() to the set; thus a pure
3833 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003834 * If there was a flag on the nodesetval, indicating that
3835 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003836 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003837 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003838 * Optimization: Create an equally sized node-set
3839 * and memcpy the content.
3840 */
3841 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3842 if (val1 == NULL)
3843 return(NULL);
3844 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003845 if (val2->nodeNr == 1)
3846 *(val1->nodeTab) = *(val2->nodeTab);
3847 else {
3848 memcpy(val1->nodeTab, val2->nodeTab,
3849 val2->nodeNr * sizeof(xmlNodePtr));
3850 }
3851 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003852 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003853 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003854#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003855 }
3856
William M. Brack08171912003-12-29 02:52:11 +00003857 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003858 initNr = val1->nodeNr;
3859
3860 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003861 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003862 /*
William M. Brack08171912003-12-29 02:52:11 +00003863 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003864 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003865 skip = 0;
3866 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003867 n1 = val1->nodeTab[j];
3868 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003869 skip = 1;
3870 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003871 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003872 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003873 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3874 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3875 ((xmlNsPtr) n2)->prefix)))
3876 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003877 skip = 1;
3878 break;
3879 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003880 }
3881 }
3882 if (skip)
3883 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003884
3885 /*
3886 * grow the nodeTab if needed
3887 */
3888 if (val1->nodeMax == 0) {
3889 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3890 sizeof(xmlNodePtr));
3891 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003892 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003893 return(NULL);
3894 }
3895 memset(val1->nodeTab, 0 ,
3896 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3897 val1->nodeMax = XML_NODESET_DEFAULT;
3898 } else if (val1->nodeNr == val1->nodeMax) {
3899 xmlNodePtr *temp;
3900
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003901 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3902 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3903 return(NULL);
3904 }
Chris Evansd7958b22011-03-23 08:13:06 +08003905 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003906 sizeof(xmlNodePtr));
3907 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003908 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003909 return(NULL);
3910 }
3911 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003912 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003913 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003914 if (n2->type == XML_NAMESPACE_DECL) {
3915 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003916
3917 val1->nodeTab[val1->nodeNr++] =
3918 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3919 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003920 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003921 }
3922
3923 return(val1);
3924}
3925
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003926
3927/**
3928 * xmlXPathNodeSetMergeAndClear:
3929 * @set1: the first NodeSet or NULL
3930 * @set2: the second NodeSet
3931 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3932 *
3933 * Merges two nodesets, all nodes from @set2 are added to @set1
3934 * if @set1 is NULL, a new set is created and copied from @set2.
3935 * Checks for duplicate nodes. Clears set2.
3936 *
3937 * Returns @set1 once extended or NULL in case of error.
3938 */
3939static xmlNodeSetPtr
3940xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3941 int hasNullEntries)
3942{
3943 if ((set1 == NULL) && (hasNullEntries == 0)) {
3944 /*
3945 * Note that doing a memcpy of the list, namespace nodes are
3946 * just assigned to set1, since set2 is cleared anyway.
3947 */
3948 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3949 if (set1 == NULL)
3950 return(NULL);
3951 if (set2->nodeNr != 0) {
3952 memcpy(set1->nodeTab, set2->nodeTab,
3953 set2->nodeNr * sizeof(xmlNodePtr));
3954 set1->nodeNr = set2->nodeNr;
3955 }
3956 } else {
3957 int i, j, initNbSet1;
3958 xmlNodePtr n1, n2;
3959
3960 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003961 set1 = xmlXPathNodeSetCreate(NULL);
3962 if (set1 == NULL)
3963 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003964
Daniel Veillard45490ae2008-07-29 09:13:19 +00003965 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003966 for (i = 0;i < set2->nodeNr;i++) {
3967 n2 = set2->nodeTab[i];
3968 /*
3969 * Skip NULLed entries.
3970 */
3971 if (n2 == NULL)
3972 continue;
3973 /*
3974 * Skip duplicates.
3975 */
3976 for (j = 0; j < initNbSet1; j++) {
3977 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003978 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003979 goto skip_node;
3980 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3981 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003982 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003983 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3984 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3985 ((xmlNsPtr) n2)->prefix)))
3986 {
3987 /*
3988 * Free the namespace node.
3989 */
3990 set2->nodeTab[i] = NULL;
3991 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3992 goto skip_node;
3993 }
3994 }
3995 }
3996 /*
3997 * grow the nodeTab if needed
3998 */
3999 if (set1->nodeMax == 0) {
4000 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4001 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4002 if (set1->nodeTab == NULL) {
4003 xmlXPathErrMemory(NULL, "merging nodeset\n");
4004 return(NULL);
4005 }
4006 memset(set1->nodeTab, 0,
4007 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4008 set1->nodeMax = XML_NODESET_DEFAULT;
4009 } else if (set1->nodeNr >= set1->nodeMax) {
4010 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004011
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004012 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4013 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4014 return(NULL);
4015 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004016 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004017 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004018 if (temp == NULL) {
4019 xmlXPathErrMemory(NULL, "merging nodeset\n");
4020 return(NULL);
4021 }
4022 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004023 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004024 }
Nick Wellnhofer9d08b342017-05-21 16:46:12 +02004025 set1->nodeTab[set1->nodeNr++] = n2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004026skip_node:
4027 {}
4028 }
4029 }
4030 set2->nodeNr = 0;
4031 return(set1);
4032}
4033
4034/**
4035 * xmlXPathNodeSetMergeAndClearNoDupls:
4036 * @set1: the first NodeSet or NULL
4037 * @set2: the second NodeSet
4038 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4039 *
4040 * Merges two nodesets, all nodes from @set2 are added to @set1
4041 * if @set1 is NULL, a new set is created and copied from @set2.
4042 * Doesn't chack for duplicate nodes. Clears set2.
4043 *
4044 * Returns @set1 once extended or NULL in case of error.
4045 */
4046static xmlNodeSetPtr
4047xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4048 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004049{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004050 if (set2 == NULL)
4051 return(set1);
4052 if ((set1 == NULL) && (hasNullEntries == 0)) {
4053 /*
4054 * Note that doing a memcpy of the list, namespace nodes are
4055 * just assigned to set1, since set2 is cleared anyway.
4056 */
4057 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4058 if (set1 == NULL)
4059 return(NULL);
4060 if (set2->nodeNr != 0) {
4061 memcpy(set1->nodeTab, set2->nodeTab,
4062 set2->nodeNr * sizeof(xmlNodePtr));
4063 set1->nodeNr = set2->nodeNr;
4064 }
4065 } else {
4066 int i;
4067 xmlNodePtr n2;
4068
4069 if (set1 == NULL)
4070 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004071 if (set1 == NULL)
4072 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004073
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004074 for (i = 0;i < set2->nodeNr;i++) {
4075 n2 = set2->nodeTab[i];
4076 /*
4077 * Skip NULLed entries.
4078 */
4079 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004080 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004081 if (set1->nodeMax == 0) {
4082 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4083 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4084 if (set1->nodeTab == NULL) {
4085 xmlXPathErrMemory(NULL, "merging nodeset\n");
4086 return(NULL);
4087 }
4088 memset(set1->nodeTab, 0,
4089 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4090 set1->nodeMax = XML_NODESET_DEFAULT;
4091 } else if (set1->nodeNr >= set1->nodeMax) {
4092 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004093
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004094 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4095 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4096 return(NULL);
4097 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004098 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004099 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004100 if (temp == NULL) {
4101 xmlXPathErrMemory(NULL, "merging nodeset\n");
4102 return(NULL);
4103 }
4104 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004105 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004106 }
4107 set1->nodeTab[set1->nodeNr++] = n2;
4108 }
4109 }
4110 set2->nodeNr = 0;
4111 return(set1);
4112}
Daniel Veillard75be0132002-03-13 10:03:35 +00004113
4114/**
Owen Taylor3473f882001-02-23 17:55:21 +00004115 * xmlXPathNodeSetDel:
4116 * @cur: the initial node set
4117 * @val: an xmlNodePtr
4118 *
4119 * Removes an xmlNodePtr from an existing NodeSet
4120 */
4121void
4122xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4123 int i;
4124
4125 if (cur == NULL) return;
4126 if (val == NULL) return;
4127
4128 /*
William M. Brack08171912003-12-29 02:52:11 +00004129 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004130 */
4131 for (i = 0;i < cur->nodeNr;i++)
4132 if (cur->nodeTab[i] == val) break;
4133
William M. Brack08171912003-12-29 02:52:11 +00004134 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004135#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004136 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004137 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4138 val->name);
4139#endif
4140 return;
4141 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004142 if ((cur->nodeTab[i] != NULL) &&
4143 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4144 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004145 cur->nodeNr--;
4146 for (;i < cur->nodeNr;i++)
4147 cur->nodeTab[i] = cur->nodeTab[i + 1];
4148 cur->nodeTab[cur->nodeNr] = NULL;
4149}
4150
4151/**
4152 * xmlXPathNodeSetRemove:
4153 * @cur: the initial node set
4154 * @val: the index to remove
4155 *
4156 * Removes an entry from an existing NodeSet list.
4157 */
4158void
4159xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4160 if (cur == NULL) return;
4161 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004162 if ((cur->nodeTab[val] != NULL) &&
4163 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4164 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004165 cur->nodeNr--;
4166 for (;val < cur->nodeNr;val++)
4167 cur->nodeTab[val] = cur->nodeTab[val + 1];
4168 cur->nodeTab[cur->nodeNr] = NULL;
4169}
4170
4171/**
4172 * xmlXPathFreeNodeSet:
4173 * @obj: the xmlNodeSetPtr to free
4174 *
4175 * Free the NodeSet compound (not the actual nodes !).
4176 */
4177void
4178xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4179 if (obj == NULL) return;
4180 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004181 int i;
4182
William M. Brack08171912003-12-29 02:52:11 +00004183 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004184 for (i = 0;i < obj->nodeNr;i++)
4185 if ((obj->nodeTab[i] != NULL) &&
4186 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4187 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004188 xmlFree(obj->nodeTab);
4189 }
Owen Taylor3473f882001-02-23 17:55:21 +00004190 xmlFree(obj);
4191}
4192
4193/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004194 * xmlXPathNodeSetClearFromPos:
4195 * @set: the node set to be cleared
4196 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004197 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004198 * Clears the list from temporary XPath objects (e.g. namespace nodes
4199 * are feed) starting with the entry at @pos, but does *not* free the list
4200 * itself. Sets the length of the list to @pos.
4201 */
4202static void
4203xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4204{
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004205 if ((set == NULL) || (pos >= set->nodeNr))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004206 return;
4207 else if ((hasNsNodes)) {
4208 int i;
4209 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004210
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004211 for (i = pos; i < set->nodeNr; i++) {
4212 node = set->nodeTab[i];
4213 if ((node != NULL) &&
4214 (node->type == XML_NAMESPACE_DECL))
4215 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004216 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004217 }
4218 set->nodeNr = pos;
4219}
4220
4221/**
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004222 * xmlXPathNodeSetClear:
4223 * @set: the node set to clear
4224 *
4225 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4226 * are feed), but does *not* free the list itself. Sets the length of the
4227 * list to 0.
4228 */
4229static void
4230xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4231{
4232 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4233}
4234
4235/**
4236 * xmlXPathNodeSetKeepLast:
4237 * @set: the node set to be cleared
4238 *
4239 * Move the last node to the first position and clear temporary XPath objects
4240 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4241 * to 1.
4242 */
4243static void
4244xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4245{
4246 int i;
4247 xmlNodePtr node;
4248
4249 if ((set == NULL) || (set->nodeNr <= 1))
4250 return;
4251 for (i = 0; i < set->nodeNr - 1; i++) {
4252 node = set->nodeTab[i];
4253 if ((node != NULL) &&
4254 (node->type == XML_NAMESPACE_DECL))
4255 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4256 }
4257 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4258 set->nodeNr = 1;
4259}
4260
4261/**
Owen Taylor3473f882001-02-23 17:55:21 +00004262 * xmlXPathFreeValueTree:
4263 * @obj: the xmlNodeSetPtr to free
4264 *
4265 * Free the NodeSet compound and the actual tree, this is different
4266 * from xmlXPathFreeNodeSet()
4267 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004268static void
Owen Taylor3473f882001-02-23 17:55:21 +00004269xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4270 int i;
4271
4272 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004273
4274 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004275 for (i = 0;i < obj->nodeNr;i++) {
4276 if (obj->nodeTab[i] != NULL) {
4277 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4278 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4279 } else {
4280 xmlFreeNodeList(obj->nodeTab[i]);
4281 }
4282 }
4283 }
Owen Taylor3473f882001-02-23 17:55:21 +00004284 xmlFree(obj->nodeTab);
4285 }
Owen Taylor3473f882001-02-23 17:55:21 +00004286 xmlFree(obj);
4287}
4288
4289#if defined(DEBUG) || defined(DEBUG_STEP)
4290/**
4291 * xmlGenericErrorContextNodeSet:
4292 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004293 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004294 *
4295 * Quick display of a NodeSet
4296 */
4297void
4298xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4299 int i;
4300
4301 if (output == NULL) output = xmlGenericErrorContext;
4302 if (obj == NULL) {
4303 fprintf(output, "NodeSet == NULL !\n");
4304 return;
4305 }
4306 if (obj->nodeNr == 0) {
4307 fprintf(output, "NodeSet is empty\n");
4308 return;
4309 }
4310 if (obj->nodeTab == NULL) {
4311 fprintf(output, " nodeTab == NULL !\n");
4312 return;
4313 }
4314 for (i = 0; i < obj->nodeNr; i++) {
4315 if (obj->nodeTab[i] == NULL) {
4316 fprintf(output, " NULL !\n");
4317 return;
4318 }
4319 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4320 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4321 fprintf(output, " /");
4322 else if (obj->nodeTab[i]->name == NULL)
4323 fprintf(output, " noname!");
4324 else fprintf(output, " %s", obj->nodeTab[i]->name);
4325 }
4326 fprintf(output, "\n");
4327}
4328#endif
4329
4330/**
4331 * xmlXPathNewNodeSet:
4332 * @val: the NodePtr value
4333 *
4334 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4335 * it with the single Node @val
4336 *
4337 * Returns the newly created object.
4338 */
4339xmlXPathObjectPtr
4340xmlXPathNewNodeSet(xmlNodePtr val) {
4341 xmlXPathObjectPtr ret;
4342
4343 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4344 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004345 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004346 return(NULL);
4347 }
4348 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4349 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004350 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004351 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004352 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004353#ifdef XP_DEBUG_OBJ_USAGE
4354 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4355#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004356 return(ret);
4357}
4358
4359/**
4360 * xmlXPathNewValueTree:
4361 * @val: the NodePtr value
4362 *
4363 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4364 * it with the tree root @val
4365 *
4366 * Returns the newly created object.
4367 */
4368xmlXPathObjectPtr
4369xmlXPathNewValueTree(xmlNodePtr val) {
4370 xmlXPathObjectPtr ret;
4371
4372 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4373 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004374 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004375 return(NULL);
4376 }
4377 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4378 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004379 ret->boolval = 1;
4380 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004381 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004382#ifdef XP_DEBUG_OBJ_USAGE
4383 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4384#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004385 return(ret);
4386}
4387
4388/**
4389 * xmlXPathNewNodeSetList:
4390 * @val: an existing NodeSet
4391 *
4392 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4393 * it with the Nodeset @val
4394 *
4395 * Returns the newly created object.
4396 */
4397xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004398xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4399{
Owen Taylor3473f882001-02-23 17:55:21 +00004400 xmlXPathObjectPtr ret;
4401 int i;
4402
4403 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004404 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004405 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004406 ret = xmlXPathNewNodeSet(NULL);
4407 else {
4408 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004409 if (ret) {
4410 for (i = 1; i < val->nodeNr; ++i) {
4411 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4412 < 0) break;
4413 }
4414 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004415 }
Owen Taylor3473f882001-02-23 17:55:21 +00004416
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004417 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004418}
4419
4420/**
4421 * xmlXPathWrapNodeSet:
4422 * @val: the NodePtr value
4423 *
4424 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4425 *
4426 * Returns the newly created object.
4427 */
4428xmlXPathObjectPtr
4429xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4430 xmlXPathObjectPtr ret;
4431
4432 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4433 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004434 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004435 return(NULL);
4436 }
4437 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4438 ret->type = XPATH_NODESET;
4439 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004440#ifdef XP_DEBUG_OBJ_USAGE
4441 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4442#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004443 return(ret);
4444}
4445
4446/**
4447 * xmlXPathFreeNodeSetList:
4448 * @obj: an existing NodeSetList object
4449 *
4450 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4451 * the list contrary to xmlXPathFreeObject().
4452 */
4453void
4454xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4455 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004456#ifdef XP_DEBUG_OBJ_USAGE
4457 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4458#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004459 xmlFree(obj);
4460}
4461
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004462/**
4463 * xmlXPathDifference:
4464 * @nodes1: a node-set
4465 * @nodes2: a node-set
4466 *
4467 * Implements the EXSLT - Sets difference() function:
4468 * node-set set:difference (node-set, node-set)
4469 *
4470 * Returns the difference between the two node sets, or nodes1 if
4471 * nodes2 is empty
4472 */
4473xmlNodeSetPtr
4474xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4475 xmlNodeSetPtr ret;
4476 int i, l1;
4477 xmlNodePtr cur;
4478
4479 if (xmlXPathNodeSetIsEmpty(nodes2))
4480 return(nodes1);
4481
4482 ret = xmlXPathNodeSetCreate(NULL);
4483 if (xmlXPathNodeSetIsEmpty(nodes1))
4484 return(ret);
4485
4486 l1 = xmlXPathNodeSetGetLength(nodes1);
4487
4488 for (i = 0; i < l1; i++) {
4489 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004490 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4491 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4492 break;
4493 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004494 }
4495 return(ret);
4496}
4497
4498/**
4499 * xmlXPathIntersection:
4500 * @nodes1: a node-set
4501 * @nodes2: a node-set
4502 *
4503 * Implements the EXSLT - Sets intersection() function:
4504 * node-set set:intersection (node-set, node-set)
4505 *
4506 * Returns a node set comprising the nodes that are within both the
4507 * node sets passed as arguments
4508 */
4509xmlNodeSetPtr
4510xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4511 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4512 int i, l1;
4513 xmlNodePtr cur;
4514
Daniel Veillardf88d8492008-04-01 08:00:31 +00004515 if (ret == NULL)
4516 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004517 if (xmlXPathNodeSetIsEmpty(nodes1))
4518 return(ret);
4519 if (xmlXPathNodeSetIsEmpty(nodes2))
4520 return(ret);
4521
4522 l1 = xmlXPathNodeSetGetLength(nodes1);
4523
4524 for (i = 0; i < l1; i++) {
4525 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004526 if (xmlXPathNodeSetContains(nodes2, cur)) {
4527 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4528 break;
4529 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004530 }
4531 return(ret);
4532}
4533
4534/**
4535 * xmlXPathDistinctSorted:
4536 * @nodes: a node-set, sorted by document order
4537 *
4538 * Implements the EXSLT - Sets distinct() function:
4539 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004540 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004541 * Returns a subset of the nodes contained in @nodes, or @nodes if
4542 * it is empty
4543 */
4544xmlNodeSetPtr
4545xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4546 xmlNodeSetPtr ret;
4547 xmlHashTablePtr hash;
4548 int i, l;
4549 xmlChar * strval;
4550 xmlNodePtr cur;
4551
4552 if (xmlXPathNodeSetIsEmpty(nodes))
4553 return(nodes);
4554
4555 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004556 if (ret == NULL)
4557 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004558 l = xmlXPathNodeSetGetLength(nodes);
4559 hash = xmlHashCreate (l);
4560 for (i = 0; i < l; i++) {
4561 cur = xmlXPathNodeSetItem(nodes, i);
4562 strval = xmlXPathCastNodeToString(cur);
4563 if (xmlHashLookup(hash, strval) == NULL) {
4564 xmlHashAddEntry(hash, strval, strval);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004565 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4566 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004567 } else {
4568 xmlFree(strval);
4569 }
4570 }
4571 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4572 return(ret);
4573}
4574
4575/**
4576 * xmlXPathDistinct:
4577 * @nodes: a node-set
4578 *
4579 * Implements the EXSLT - Sets distinct() function:
4580 * node-set set:distinct (node-set)
4581 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4582 * is called with the sorted node-set
4583 *
4584 * Returns a subset of the nodes contained in @nodes, or @nodes if
4585 * it is empty
4586 */
4587xmlNodeSetPtr
4588xmlXPathDistinct (xmlNodeSetPtr nodes) {
4589 if (xmlXPathNodeSetIsEmpty(nodes))
4590 return(nodes);
4591
4592 xmlXPathNodeSetSort(nodes);
4593 return(xmlXPathDistinctSorted(nodes));
4594}
4595
4596/**
4597 * xmlXPathHasSameNodes:
4598 * @nodes1: a node-set
4599 * @nodes2: a node-set
4600 *
4601 * Implements the EXSLT - Sets has-same-nodes function:
4602 * boolean set:has-same-node(node-set, node-set)
4603 *
4604 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4605 * otherwise
4606 */
4607int
4608xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4609 int i, l;
4610 xmlNodePtr cur;
4611
4612 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4613 xmlXPathNodeSetIsEmpty(nodes2))
4614 return(0);
4615
4616 l = xmlXPathNodeSetGetLength(nodes1);
4617 for (i = 0; i < l; i++) {
4618 cur = xmlXPathNodeSetItem(nodes1, i);
4619 if (xmlXPathNodeSetContains(nodes2, cur))
4620 return(1);
4621 }
4622 return(0);
4623}
4624
4625/**
4626 * xmlXPathNodeLeadingSorted:
4627 * @nodes: a node-set, sorted by document order
4628 * @node: a node
4629 *
4630 * Implements the EXSLT - Sets leading() function:
4631 * node-set set:leading (node-set, node-set)
4632 *
4633 * Returns the nodes in @nodes that precede @node in document order,
4634 * @nodes if @node is NULL or an empty node-set if @nodes
4635 * doesn't contain @node
4636 */
4637xmlNodeSetPtr
4638xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4639 int i, l;
4640 xmlNodePtr cur;
4641 xmlNodeSetPtr ret;
4642
4643 if (node == NULL)
4644 return(nodes);
4645
4646 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004647 if (ret == NULL)
4648 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004649 if (xmlXPathNodeSetIsEmpty(nodes) ||
4650 (!xmlXPathNodeSetContains(nodes, node)))
4651 return(ret);
4652
4653 l = xmlXPathNodeSetGetLength(nodes);
4654 for (i = 0; i < l; i++) {
4655 cur = xmlXPathNodeSetItem(nodes, i);
4656 if (cur == node)
4657 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004658 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4659 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004660 }
4661 return(ret);
4662}
4663
4664/**
4665 * xmlXPathNodeLeading:
4666 * @nodes: a node-set
4667 * @node: a node
4668 *
4669 * Implements the EXSLT - Sets leading() function:
4670 * node-set set:leading (node-set, node-set)
4671 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4672 * is called.
4673 *
4674 * Returns the nodes in @nodes that precede @node in document order,
4675 * @nodes if @node is NULL or an empty node-set if @nodes
4676 * doesn't contain @node
4677 */
4678xmlNodeSetPtr
4679xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4680 xmlXPathNodeSetSort(nodes);
4681 return(xmlXPathNodeLeadingSorted(nodes, node));
4682}
4683
4684/**
4685 * xmlXPathLeadingSorted:
4686 * @nodes1: a node-set, sorted by document order
4687 * @nodes2: a node-set, sorted by document order
4688 *
4689 * Implements the EXSLT - Sets leading() function:
4690 * node-set set:leading (node-set, node-set)
4691 *
4692 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4693 * in document order, @nodes1 if @nodes2 is NULL or empty or
4694 * an empty node-set if @nodes1 doesn't contain @nodes2
4695 */
4696xmlNodeSetPtr
4697xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4698 if (xmlXPathNodeSetIsEmpty(nodes2))
4699 return(nodes1);
4700 return(xmlXPathNodeLeadingSorted(nodes1,
4701 xmlXPathNodeSetItem(nodes2, 1)));
4702}
4703
4704/**
4705 * xmlXPathLeading:
4706 * @nodes1: a node-set
4707 * @nodes2: a node-set
4708 *
4709 * Implements the EXSLT - Sets leading() function:
4710 * node-set set:leading (node-set, node-set)
4711 * @nodes1 and @nodes2 are sorted by document order, then
4712 * #exslSetsLeadingSorted is called.
4713 *
4714 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4715 * in document order, @nodes1 if @nodes2 is NULL or empty or
4716 * an empty node-set if @nodes1 doesn't contain @nodes2
4717 */
4718xmlNodeSetPtr
4719xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4720 if (xmlXPathNodeSetIsEmpty(nodes2))
4721 return(nodes1);
4722 if (xmlXPathNodeSetIsEmpty(nodes1))
4723 return(xmlXPathNodeSetCreate(NULL));
4724 xmlXPathNodeSetSort(nodes1);
4725 xmlXPathNodeSetSort(nodes2);
4726 return(xmlXPathNodeLeadingSorted(nodes1,
4727 xmlXPathNodeSetItem(nodes2, 1)));
4728}
4729
4730/**
4731 * xmlXPathNodeTrailingSorted:
4732 * @nodes: a node-set, sorted by document order
4733 * @node: a node
4734 *
4735 * Implements the EXSLT - Sets trailing() function:
4736 * node-set set:trailing (node-set, node-set)
4737 *
4738 * Returns the nodes in @nodes that follow @node in document order,
4739 * @nodes if @node is NULL or an empty node-set if @nodes
4740 * doesn't contain @node
4741 */
4742xmlNodeSetPtr
4743xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4744 int i, l;
4745 xmlNodePtr cur;
4746 xmlNodeSetPtr ret;
4747
4748 if (node == NULL)
4749 return(nodes);
4750
4751 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004752 if (ret == NULL)
4753 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004754 if (xmlXPathNodeSetIsEmpty(nodes) ||
4755 (!xmlXPathNodeSetContains(nodes, node)))
4756 return(ret);
4757
4758 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004759 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004760 cur = xmlXPathNodeSetItem(nodes, i);
4761 if (cur == node)
4762 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004763 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4764 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004765 }
William M. Brack97ac8192007-06-06 17:19:24 +00004766 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004767 return(ret);
4768}
4769
4770/**
4771 * xmlXPathNodeTrailing:
4772 * @nodes: a node-set
4773 * @node: a node
4774 *
4775 * Implements the EXSLT - Sets trailing() function:
4776 * node-set set:trailing (node-set, node-set)
4777 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4778 * is called.
4779 *
4780 * Returns the nodes in @nodes that follow @node in document order,
4781 * @nodes if @node is NULL or an empty node-set if @nodes
4782 * doesn't contain @node
4783 */
4784xmlNodeSetPtr
4785xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4786 xmlXPathNodeSetSort(nodes);
4787 return(xmlXPathNodeTrailingSorted(nodes, node));
4788}
4789
4790/**
4791 * xmlXPathTrailingSorted:
4792 * @nodes1: a node-set, sorted by document order
4793 * @nodes2: a node-set, sorted by document order
4794 *
4795 * Implements the EXSLT - Sets trailing() function:
4796 * node-set set:trailing (node-set, node-set)
4797 *
4798 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4799 * in document order, @nodes1 if @nodes2 is NULL or empty or
4800 * an empty node-set if @nodes1 doesn't contain @nodes2
4801 */
4802xmlNodeSetPtr
4803xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4804 if (xmlXPathNodeSetIsEmpty(nodes2))
4805 return(nodes1);
4806 return(xmlXPathNodeTrailingSorted(nodes1,
4807 xmlXPathNodeSetItem(nodes2, 0)));
4808}
4809
4810/**
4811 * xmlXPathTrailing:
4812 * @nodes1: a node-set
4813 * @nodes2: a node-set
4814 *
4815 * Implements the EXSLT - Sets trailing() function:
4816 * node-set set:trailing (node-set, node-set)
4817 * @nodes1 and @nodes2 are sorted by document order, then
4818 * #xmlXPathTrailingSorted is called.
4819 *
4820 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4821 * in document order, @nodes1 if @nodes2 is NULL or empty or
4822 * an empty node-set if @nodes1 doesn't contain @nodes2
4823 */
4824xmlNodeSetPtr
4825xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4826 if (xmlXPathNodeSetIsEmpty(nodes2))
4827 return(nodes1);
4828 if (xmlXPathNodeSetIsEmpty(nodes1))
4829 return(xmlXPathNodeSetCreate(NULL));
4830 xmlXPathNodeSetSort(nodes1);
4831 xmlXPathNodeSetSort(nodes2);
4832 return(xmlXPathNodeTrailingSorted(nodes1,
4833 xmlXPathNodeSetItem(nodes2, 0)));
4834}
4835
Owen Taylor3473f882001-02-23 17:55:21 +00004836/************************************************************************
4837 * *
4838 * Routines to handle extra functions *
4839 * *
4840 ************************************************************************/
4841
4842/**
4843 * xmlXPathRegisterFunc:
4844 * @ctxt: the XPath context
4845 * @name: the function name
4846 * @f: the function implementation or NULL
4847 *
4848 * Register a new function. If @f is NULL it unregisters the function
4849 *
4850 * Returns 0 in case of success, -1 in case of error
4851 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004852int
Owen Taylor3473f882001-02-23 17:55:21 +00004853xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4854 xmlXPathFunction f) {
4855 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4856}
4857
4858/**
4859 * xmlXPathRegisterFuncNS:
4860 * @ctxt: the XPath context
4861 * @name: the function name
4862 * @ns_uri: the function namespace URI
4863 * @f: the function implementation or NULL
4864 *
4865 * Register a new function. If @f is NULL it unregisters the function
4866 *
4867 * Returns 0 in case of success, -1 in case of error
4868 */
4869int
4870xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4871 const xmlChar *ns_uri, xmlXPathFunction f) {
4872 if (ctxt == NULL)
4873 return(-1);
4874 if (name == NULL)
4875 return(-1);
4876
4877 if (ctxt->funcHash == NULL)
4878 ctxt->funcHash = xmlHashCreate(0);
4879 if (ctxt->funcHash == NULL)
4880 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004881 if (f == NULL)
4882 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004883 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004884}
4885
4886/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004887 * xmlXPathRegisterFuncLookup:
4888 * @ctxt: the XPath context
4889 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004890 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004891 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004892 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004893 */
4894void
4895xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4896 xmlXPathFuncLookupFunc f,
4897 void *funcCtxt) {
4898 if (ctxt == NULL)
4899 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004900 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004901 ctxt->funcLookupData = funcCtxt;
4902}
4903
4904/**
Owen Taylor3473f882001-02-23 17:55:21 +00004905 * xmlXPathFunctionLookup:
4906 * @ctxt: the XPath context
4907 * @name: the function name
4908 *
4909 * Search in the Function array of the context for the given
4910 * function.
4911 *
4912 * Returns the xmlXPathFunction or NULL if not found
4913 */
4914xmlXPathFunction
4915xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004916 if (ctxt == NULL)
4917 return (NULL);
4918
4919 if (ctxt->funcLookupFunc != NULL) {
4920 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004921 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004922
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004923 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004924 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004925 if (ret != NULL)
4926 return(ret);
4927 }
Owen Taylor3473f882001-02-23 17:55:21 +00004928 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4929}
4930
4931/**
4932 * xmlXPathFunctionLookupNS:
4933 * @ctxt: the XPath context
4934 * @name: the function name
4935 * @ns_uri: the function namespace URI
4936 *
4937 * Search in the Function array of the context for the given
4938 * function.
4939 *
4940 * Returns the xmlXPathFunction or NULL if not found
4941 */
4942xmlXPathFunction
4943xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4944 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004945 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004946
Owen Taylor3473f882001-02-23 17:55:21 +00004947 if (ctxt == NULL)
4948 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004949 if (name == NULL)
4950 return(NULL);
4951
Thomas Broyerba4ad322001-07-26 16:55:21 +00004952 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004953 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004954
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004955 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004956 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004957 if (ret != NULL)
4958 return(ret);
4959 }
4960
4961 if (ctxt->funcHash == NULL)
4962 return(NULL);
4963
William M. Brackad0e67c2004-12-01 14:35:10 +00004964 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4965 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004966}
4967
4968/**
4969 * xmlXPathRegisteredFuncsCleanup:
4970 * @ctxt: the XPath context
4971 *
4972 * Cleanup the XPath context data associated to registered functions
4973 */
4974void
4975xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4976 if (ctxt == NULL)
4977 return;
4978
4979 xmlHashFree(ctxt->funcHash, NULL);
4980 ctxt->funcHash = NULL;
4981}
4982
4983/************************************************************************
4984 * *
William M. Brack08171912003-12-29 02:52:11 +00004985 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004986 * *
4987 ************************************************************************/
4988
4989/**
4990 * xmlXPathRegisterVariable:
4991 * @ctxt: the XPath context
4992 * @name: the variable name
4993 * @value: the variable value or NULL
4994 *
4995 * Register a new variable value. If @value is NULL it unregisters
4996 * the variable
4997 *
4998 * Returns 0 in case of success, -1 in case of error
4999 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00005000int
Owen Taylor3473f882001-02-23 17:55:21 +00005001xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5002 xmlXPathObjectPtr value) {
5003 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5004}
5005
5006/**
5007 * xmlXPathRegisterVariableNS:
5008 * @ctxt: the XPath context
5009 * @name: the variable name
5010 * @ns_uri: the variable namespace URI
5011 * @value: the variable value or NULL
5012 *
5013 * Register a new variable value. If @value is NULL it unregisters
5014 * the variable
5015 *
5016 * Returns 0 in case of success, -1 in case of error
5017 */
5018int
5019xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5020 const xmlChar *ns_uri,
5021 xmlXPathObjectPtr value) {
5022 if (ctxt == NULL)
5023 return(-1);
5024 if (name == NULL)
5025 return(-1);
5026
5027 if (ctxt->varHash == NULL)
5028 ctxt->varHash = xmlHashCreate(0);
5029 if (ctxt->varHash == NULL)
5030 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00005031 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005032 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00005033 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00005034 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5035 (void *) value,
5036 (xmlHashDeallocator)xmlXPathFreeObject));
5037}
5038
5039/**
5040 * xmlXPathRegisterVariableLookup:
5041 * @ctxt: the XPath context
5042 * @f: the lookup function
5043 * @data: the lookup data
5044 *
5045 * register an external mechanism to do variable lookup
5046 */
5047void
5048xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5049 xmlXPathVariableLookupFunc f, void *data) {
5050 if (ctxt == NULL)
5051 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00005052 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00005053 ctxt->varLookupData = data;
5054}
5055
5056/**
5057 * xmlXPathVariableLookup:
5058 * @ctxt: the XPath context
5059 * @name: the variable name
5060 *
5061 * Search in the Variable array of the context for the given
5062 * variable value.
5063 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005064 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005065 */
5066xmlXPathObjectPtr
5067xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5068 if (ctxt == NULL)
5069 return(NULL);
5070
5071 if (ctxt->varLookupFunc != NULL) {
5072 xmlXPathObjectPtr ret;
5073
5074 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5075 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00005076 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005077 }
5078 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5079}
5080
5081/**
5082 * xmlXPathVariableLookupNS:
5083 * @ctxt: the XPath context
5084 * @name: the variable name
5085 * @ns_uri: the variable namespace URI
5086 *
5087 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005088 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005089 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005090 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005091 */
5092xmlXPathObjectPtr
5093xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5094 const xmlChar *ns_uri) {
5095 if (ctxt == NULL)
5096 return(NULL);
5097
5098 if (ctxt->varLookupFunc != NULL) {
5099 xmlXPathObjectPtr ret;
5100
5101 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5102 (ctxt->varLookupData, name, ns_uri);
5103 if (ret != NULL) return(ret);
5104 }
5105
5106 if (ctxt->varHash == NULL)
5107 return(NULL);
5108 if (name == NULL)
5109 return(NULL);
5110
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005111 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005112 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005113}
5114
5115/**
5116 * xmlXPathRegisteredVariablesCleanup:
5117 * @ctxt: the XPath context
5118 *
5119 * Cleanup the XPath context data associated to registered variables
5120 */
5121void
5122xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5123 if (ctxt == NULL)
5124 return;
5125
Daniel Veillard76d66f42001-05-16 21:05:17 +00005126 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005127 ctxt->varHash = NULL;
5128}
5129
5130/**
5131 * xmlXPathRegisterNs:
5132 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005133 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005134 * @ns_uri: the namespace name
5135 *
5136 * Register a new namespace. If @ns_uri is NULL it unregisters
5137 * the namespace
5138 *
5139 * Returns 0 in case of success, -1 in case of error
5140 */
5141int
5142xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5143 const xmlChar *ns_uri) {
5144 if (ctxt == NULL)
5145 return(-1);
5146 if (prefix == NULL)
5147 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005148 if (prefix[0] == 0)
5149 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005150
5151 if (ctxt->nsHash == NULL)
5152 ctxt->nsHash = xmlHashCreate(10);
5153 if (ctxt->nsHash == NULL)
5154 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005155 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005156 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005157 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005158 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005159 (xmlHashDeallocator)xmlFree));
5160}
5161
5162/**
5163 * xmlXPathNsLookup:
5164 * @ctxt: the XPath context
5165 * @prefix: the namespace prefix value
5166 *
5167 * Search in the namespace declaration array of the context for the given
5168 * namespace name associated to the given prefix
5169 *
5170 * Returns the value or NULL if not found
5171 */
5172const xmlChar *
5173xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5174 if (ctxt == NULL)
5175 return(NULL);
5176 if (prefix == NULL)
5177 return(NULL);
5178
5179#ifdef XML_XML_NAMESPACE
5180 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5181 return(XML_XML_NAMESPACE);
5182#endif
5183
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005184 if (ctxt->namespaces != NULL) {
5185 int i;
5186
5187 for (i = 0;i < ctxt->nsNr;i++) {
5188 if ((ctxt->namespaces[i] != NULL) &&
5189 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5190 return(ctxt->namespaces[i]->href);
5191 }
5192 }
Owen Taylor3473f882001-02-23 17:55:21 +00005193
5194 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5195}
5196
5197/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005198 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005199 * @ctxt: the XPath context
5200 *
5201 * Cleanup the XPath context data associated to registered variables
5202 */
5203void
5204xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5205 if (ctxt == NULL)
5206 return;
5207
Daniel Veillard42766c02002-08-22 20:52:17 +00005208 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005209 ctxt->nsHash = NULL;
5210}
5211
5212/************************************************************************
5213 * *
5214 * Routines to handle Values *
5215 * *
5216 ************************************************************************/
5217
William M. Brack08171912003-12-29 02:52:11 +00005218/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005219
5220/**
5221 * xmlXPathNewFloat:
5222 * @val: the double value
5223 *
5224 * Create a new xmlXPathObjectPtr of type double and of value @val
5225 *
5226 * Returns the newly created object.
5227 */
5228xmlXPathObjectPtr
5229xmlXPathNewFloat(double val) {
5230 xmlXPathObjectPtr ret;
5231
5232 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5233 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005234 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005235 return(NULL);
5236 }
5237 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5238 ret->type = XPATH_NUMBER;
5239 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005240#ifdef XP_DEBUG_OBJ_USAGE
5241 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5242#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005243 return(ret);
5244}
5245
5246/**
5247 * xmlXPathNewBoolean:
5248 * @val: the boolean value
5249 *
5250 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5251 *
5252 * Returns the newly created object.
5253 */
5254xmlXPathObjectPtr
5255xmlXPathNewBoolean(int val) {
5256 xmlXPathObjectPtr ret;
5257
5258 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5259 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005260 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005261 return(NULL);
5262 }
5263 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5264 ret->type = XPATH_BOOLEAN;
5265 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005266#ifdef XP_DEBUG_OBJ_USAGE
5267 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5268#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005269 return(ret);
5270}
5271
5272/**
5273 * xmlXPathNewString:
5274 * @val: the xmlChar * value
5275 *
5276 * Create a new xmlXPathObjectPtr of type string and of value @val
5277 *
5278 * Returns the newly created object.
5279 */
5280xmlXPathObjectPtr
5281xmlXPathNewString(const xmlChar *val) {
5282 xmlXPathObjectPtr ret;
5283
5284 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5285 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005286 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005287 return(NULL);
5288 }
5289 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5290 ret->type = XPATH_STRING;
5291 if (val != NULL)
5292 ret->stringval = xmlStrdup(val);
5293 else
5294 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005295#ifdef XP_DEBUG_OBJ_USAGE
5296 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5297#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005298 return(ret);
5299}
5300
5301/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005302 * xmlXPathWrapString:
5303 * @val: the xmlChar * value
5304 *
5305 * Wraps the @val string into an XPath object.
5306 *
5307 * Returns the newly created object.
5308 */
5309xmlXPathObjectPtr
5310xmlXPathWrapString (xmlChar *val) {
5311 xmlXPathObjectPtr ret;
5312
5313 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5314 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005315 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005316 return(NULL);
5317 }
5318 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5319 ret->type = XPATH_STRING;
5320 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005321#ifdef XP_DEBUG_OBJ_USAGE
5322 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5323#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005324 return(ret);
5325}
5326
5327/**
Owen Taylor3473f882001-02-23 17:55:21 +00005328 * xmlXPathNewCString:
5329 * @val: the char * value
5330 *
5331 * Create a new xmlXPathObjectPtr of type string and of value @val
5332 *
5333 * Returns the newly created object.
5334 */
5335xmlXPathObjectPtr
5336xmlXPathNewCString(const char *val) {
5337 xmlXPathObjectPtr ret;
5338
5339 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5340 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005341 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005342 return(NULL);
5343 }
5344 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5345 ret->type = XPATH_STRING;
5346 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005347#ifdef XP_DEBUG_OBJ_USAGE
5348 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5349#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005350 return(ret);
5351}
5352
5353/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005354 * xmlXPathWrapCString:
5355 * @val: the char * value
5356 *
5357 * Wraps a string into an XPath object.
5358 *
5359 * Returns the newly created object.
5360 */
5361xmlXPathObjectPtr
5362xmlXPathWrapCString (char * val) {
5363 return(xmlXPathWrapString((xmlChar *)(val)));
5364}
5365
5366/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005367 * xmlXPathWrapExternal:
5368 * @val: the user data
5369 *
5370 * Wraps the @val data into an XPath object.
5371 *
5372 * Returns the newly created object.
5373 */
5374xmlXPathObjectPtr
5375xmlXPathWrapExternal (void *val) {
5376 xmlXPathObjectPtr ret;
5377
5378 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5379 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005380 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005381 return(NULL);
5382 }
5383 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5384 ret->type = XPATH_USERS;
5385 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005386#ifdef XP_DEBUG_OBJ_USAGE
5387 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5388#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005389 return(ret);
5390}
5391
5392/**
Owen Taylor3473f882001-02-23 17:55:21 +00005393 * xmlXPathObjectCopy:
5394 * @val: the original object
5395 *
5396 * allocate a new copy of a given object
5397 *
5398 * Returns the newly created object.
5399 */
5400xmlXPathObjectPtr
5401xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5402 xmlXPathObjectPtr ret;
5403
5404 if (val == NULL)
5405 return(NULL);
5406
5407 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5408 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005409 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005410 return(NULL);
5411 }
5412 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005413#ifdef XP_DEBUG_OBJ_USAGE
5414 xmlXPathDebugObjUsageRequested(NULL, val->type);
5415#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005416 switch (val->type) {
5417 case XPATH_BOOLEAN:
5418 case XPATH_NUMBER:
5419 case XPATH_POINT:
5420 case XPATH_RANGE:
5421 break;
5422 case XPATH_STRING:
5423 ret->stringval = xmlStrdup(val->stringval);
5424 break;
5425 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005426#if 0
5427/*
5428 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5429 this previous handling is no longer correct, and can cause some serious
5430 problems (ref. bug 145547)
5431*/
Owen Taylor3473f882001-02-23 17:55:21 +00005432 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005433 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005434 xmlNodePtr cur, tmp;
5435 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005436
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005437 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005438 top = xmlNewDoc(NULL);
5439 top->name = (char *)
5440 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005441 ret->user = top;
5442 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005443 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005444 cur = val->nodesetval->nodeTab[0]->children;
5445 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005446 tmp = xmlDocCopyNode(cur, top, 1);
5447 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005448 cur = cur->next;
5449 }
5450 }
William M. Bracke9449c52004-07-11 14:41:20 +00005451
Daniel Veillard9adc0462003-03-24 18:39:54 +00005452 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005453 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005454 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005455 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005456 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005457#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005458 case XPATH_NODESET:
5459 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005460 /* Do not deallocate the copied tree value */
5461 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005462 break;
5463 case XPATH_LOCATIONSET:
5464#ifdef LIBXML_XPTR_ENABLED
5465 {
5466 xmlLocationSetPtr loc = val->user;
5467 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5468 break;
5469 }
5470#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005471 case XPATH_USERS:
5472 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005473 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005474 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005475 xmlGenericError(xmlGenericErrorContext,
5476 "xmlXPathObjectCopy: unsupported type %d\n",
5477 val->type);
5478 break;
5479 }
5480 return(ret);
5481}
5482
5483/**
5484 * xmlXPathFreeObject:
5485 * @obj: the object to free
5486 *
5487 * Free up an xmlXPathObjectPtr object.
5488 */
5489void
5490xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5491 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005492 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005493 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005494#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005495 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005496 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005497 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005498 } else
5499#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005500 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005501 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005502 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005503 } else {
5504 if (obj->nodesetval != NULL)
5505 xmlXPathFreeNodeSet(obj->nodesetval);
5506 }
Owen Taylor3473f882001-02-23 17:55:21 +00005507#ifdef LIBXML_XPTR_ENABLED
5508 } else if (obj->type == XPATH_LOCATIONSET) {
5509 if (obj->user != NULL)
5510 xmlXPtrFreeLocationSet(obj->user);
5511#endif
5512 } else if (obj->type == XPATH_STRING) {
5513 if (obj->stringval != NULL)
5514 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005515 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005516#ifdef XP_DEBUG_OBJ_USAGE
5517 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5518#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005519 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005520}
Owen Taylor3473f882001-02-23 17:55:21 +00005521
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005522/**
5523 * xmlXPathReleaseObject:
5524 * @obj: the xmlXPathObjectPtr to free or to cache
5525 *
5526 * Depending on the state of the cache this frees the given
5527 * XPath object or stores it in the cache.
5528 */
5529static void
5530xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5531{
5532#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5533 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5534 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5535
5536#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5537
5538 if (obj == NULL)
5539 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005540 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005541 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005542 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005543 xmlXPathContextCachePtr cache =
5544 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005545
5546 switch (obj->type) {
5547 case XPATH_NODESET:
5548 case XPATH_XSLT_TREE:
5549 if (obj->nodesetval != NULL) {
5550 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005551 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005552 * It looks like the @boolval is used for
5553 * evaluation if this an XSLT Result Tree Fragment.
5554 * TODO: Check if this assumption is correct.
5555 */
5556 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5557 xmlXPathFreeValueTree(obj->nodesetval);
5558 obj->nodesetval = NULL;
5559 } else if ((obj->nodesetval->nodeMax <= 40) &&
5560 (XP_CACHE_WANTS(cache->nodesetObjs,
5561 cache->maxNodeset)))
5562 {
5563 XP_CACHE_ADD(cache->nodesetObjs, obj);
5564 goto obj_cached;
5565 } else {
5566 xmlXPathFreeNodeSet(obj->nodesetval);
5567 obj->nodesetval = NULL;
5568 }
5569 }
5570 break;
5571 case XPATH_STRING:
5572 if (obj->stringval != NULL)
5573 xmlFree(obj->stringval);
5574
5575 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5576 XP_CACHE_ADD(cache->stringObjs, obj);
5577 goto obj_cached;
5578 }
5579 break;
5580 case XPATH_BOOLEAN:
5581 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5582 XP_CACHE_ADD(cache->booleanObjs, obj);
5583 goto obj_cached;
5584 }
5585 break;
5586 case XPATH_NUMBER:
5587 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5588 XP_CACHE_ADD(cache->numberObjs, obj);
5589 goto obj_cached;
5590 }
5591 break;
5592#ifdef LIBXML_XPTR_ENABLED
5593 case XPATH_LOCATIONSET:
5594 if (obj->user != NULL) {
5595 xmlXPtrFreeLocationSet(obj->user);
5596 }
5597 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005598#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005599 default:
5600 goto free_obj;
5601 }
5602
5603 /*
5604 * Fallback to adding to the misc-objects slot.
5605 */
5606 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5607 XP_CACHE_ADD(cache->miscObjs, obj);
5608 } else
5609 goto free_obj;
5610
5611obj_cached:
5612
5613#ifdef XP_DEBUG_OBJ_USAGE
5614 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5615#endif
5616
5617 if (obj->nodesetval != NULL) {
5618 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005619
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005620 /*
5621 * TODO: Due to those nasty ns-nodes, we need to traverse
5622 * the list and free the ns-nodes.
5623 * URGENT TODO: Check if it's actually slowing things down.
5624 * Maybe we shouldn't try to preserve the list.
5625 */
5626 if (tmpset->nodeNr > 1) {
5627 int i;
5628 xmlNodePtr node;
5629
5630 for (i = 0; i < tmpset->nodeNr; i++) {
5631 node = tmpset->nodeTab[i];
5632 if ((node != NULL) &&
5633 (node->type == XML_NAMESPACE_DECL))
5634 {
5635 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5636 }
5637 }
5638 } else if (tmpset->nodeNr == 1) {
5639 if ((tmpset->nodeTab[0] != NULL) &&
5640 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5641 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005642 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005643 tmpset->nodeNr = 0;
5644 memset(obj, 0, sizeof(xmlXPathObject));
5645 obj->nodesetval = tmpset;
5646 } else
5647 memset(obj, 0, sizeof(xmlXPathObject));
5648
5649 return;
5650
5651free_obj:
5652 /*
5653 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005654 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005655 if (obj->nodesetval != NULL)
5656 xmlXPathFreeNodeSet(obj->nodesetval);
5657#ifdef XP_DEBUG_OBJ_USAGE
5658 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5659#endif
5660 xmlFree(obj);
5661 }
5662 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005663}
5664
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005665
5666/************************************************************************
5667 * *
5668 * Type Casting Routines *
5669 * *
5670 ************************************************************************/
5671
5672/**
5673 * xmlXPathCastBooleanToString:
5674 * @val: a boolean
5675 *
5676 * Converts a boolean to its string value.
5677 *
5678 * Returns a newly allocated string.
5679 */
5680xmlChar *
5681xmlXPathCastBooleanToString (int val) {
5682 xmlChar *ret;
5683 if (val)
5684 ret = xmlStrdup((const xmlChar *) "true");
5685 else
5686 ret = xmlStrdup((const xmlChar *) "false");
5687 return(ret);
5688}
5689
5690/**
5691 * xmlXPathCastNumberToString:
5692 * @val: a number
5693 *
5694 * Converts a number to its string value.
5695 *
5696 * Returns a newly allocated string.
5697 */
5698xmlChar *
5699xmlXPathCastNumberToString (double val) {
5700 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005701 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005702 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005703 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005704 break;
5705 case -1:
5706 ret = xmlStrdup((const xmlChar *) "-Infinity");
5707 break;
5708 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005709 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005710 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005711 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5712 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005713 } else {
5714 /* could be improved */
5715 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005716 xmlXPathFormatNumber(val, buf, 99);
5717 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005718 ret = xmlStrdup((const xmlChar *) buf);
5719 }
5720 }
5721 return(ret);
5722}
5723
5724/**
5725 * xmlXPathCastNodeToString:
5726 * @node: a node
5727 *
5728 * Converts a node to its string value.
5729 *
5730 * Returns a newly allocated string.
5731 */
5732xmlChar *
5733xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005734xmlChar *ret;
5735 if ((ret = xmlNodeGetContent(node)) == NULL)
5736 ret = xmlStrdup((const xmlChar *) "");
5737 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005738}
5739
5740/**
5741 * xmlXPathCastNodeSetToString:
5742 * @ns: a node-set
5743 *
5744 * Converts a node-set to its string value.
5745 *
5746 * Returns a newly allocated string.
5747 */
5748xmlChar *
5749xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5750 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5751 return(xmlStrdup((const xmlChar *) ""));
5752
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005753 if (ns->nodeNr > 1)
5754 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005755 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5756}
5757
5758/**
5759 * xmlXPathCastToString:
5760 * @val: an XPath object
5761 *
5762 * Converts an existing object to its string() equivalent
5763 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005764 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005765 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005766 */
5767xmlChar *
5768xmlXPathCastToString(xmlXPathObjectPtr val) {
5769 xmlChar *ret = NULL;
5770
5771 if (val == NULL)
5772 return(xmlStrdup((const xmlChar *) ""));
5773 switch (val->type) {
5774 case XPATH_UNDEFINED:
5775#ifdef DEBUG_EXPR
5776 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5777#endif
5778 ret = xmlStrdup((const xmlChar *) "");
5779 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005780 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005781 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005782 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5783 break;
5784 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005785 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005786 case XPATH_BOOLEAN:
5787 ret = xmlXPathCastBooleanToString(val->boolval);
5788 break;
5789 case XPATH_NUMBER: {
5790 ret = xmlXPathCastNumberToString(val->floatval);
5791 break;
5792 }
5793 case XPATH_USERS:
5794 case XPATH_POINT:
5795 case XPATH_RANGE:
5796 case XPATH_LOCATIONSET:
5797 TODO
5798 ret = xmlStrdup((const xmlChar *) "");
5799 break;
5800 }
5801 return(ret);
5802}
5803
5804/**
5805 * xmlXPathConvertString:
5806 * @val: an XPath object
5807 *
5808 * Converts an existing object to its string() equivalent
5809 *
5810 * Returns the new object, the old one is freed (or the operation
5811 * is done directly on @val)
5812 */
5813xmlXPathObjectPtr
5814xmlXPathConvertString(xmlXPathObjectPtr val) {
5815 xmlChar *res = NULL;
5816
5817 if (val == NULL)
5818 return(xmlXPathNewCString(""));
5819
5820 switch (val->type) {
5821 case XPATH_UNDEFINED:
5822#ifdef DEBUG_EXPR
5823 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5824#endif
5825 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005826 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005827 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005828 res = xmlXPathCastNodeSetToString(val->nodesetval);
5829 break;
5830 case XPATH_STRING:
5831 return(val);
5832 case XPATH_BOOLEAN:
5833 res = xmlXPathCastBooleanToString(val->boolval);
5834 break;
5835 case XPATH_NUMBER:
5836 res = xmlXPathCastNumberToString(val->floatval);
5837 break;
5838 case XPATH_USERS:
5839 case XPATH_POINT:
5840 case XPATH_RANGE:
5841 case XPATH_LOCATIONSET:
5842 TODO;
5843 break;
5844 }
5845 xmlXPathFreeObject(val);
5846 if (res == NULL)
5847 return(xmlXPathNewCString(""));
5848 return(xmlXPathWrapString(res));
5849}
5850
5851/**
5852 * xmlXPathCastBooleanToNumber:
5853 * @val: a boolean
5854 *
5855 * Converts a boolean to its number value
5856 *
5857 * Returns the number value
5858 */
5859double
5860xmlXPathCastBooleanToNumber(int val) {
5861 if (val)
5862 return(1.0);
5863 return(0.0);
5864}
5865
5866/**
5867 * xmlXPathCastStringToNumber:
5868 * @val: a string
5869 *
5870 * Converts a string to its number value
5871 *
5872 * Returns the number value
5873 */
5874double
5875xmlXPathCastStringToNumber(const xmlChar * val) {
5876 return(xmlXPathStringEvalNumber(val));
5877}
5878
5879/**
5880 * xmlXPathCastNodeToNumber:
5881 * @node: a node
5882 *
5883 * Converts a node to its number value
5884 *
5885 * Returns the number value
5886 */
5887double
5888xmlXPathCastNodeToNumber (xmlNodePtr node) {
5889 xmlChar *strval;
5890 double ret;
5891
5892 if (node == NULL)
5893 return(xmlXPathNAN);
5894 strval = xmlXPathCastNodeToString(node);
5895 if (strval == NULL)
5896 return(xmlXPathNAN);
5897 ret = xmlXPathCastStringToNumber(strval);
5898 xmlFree(strval);
5899
5900 return(ret);
5901}
5902
5903/**
5904 * xmlXPathCastNodeSetToNumber:
5905 * @ns: a node-set
5906 *
5907 * Converts a node-set to its number value
5908 *
5909 * Returns the number value
5910 */
5911double
5912xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5913 xmlChar *str;
5914 double ret;
5915
5916 if (ns == NULL)
5917 return(xmlXPathNAN);
5918 str = xmlXPathCastNodeSetToString(ns);
5919 ret = xmlXPathCastStringToNumber(str);
5920 xmlFree(str);
5921 return(ret);
5922}
5923
5924/**
5925 * xmlXPathCastToNumber:
5926 * @val: an XPath object
5927 *
5928 * Converts an XPath object to its number value
5929 *
5930 * Returns the number value
5931 */
5932double
5933xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5934 double ret = 0.0;
5935
5936 if (val == NULL)
5937 return(xmlXPathNAN);
5938 switch (val->type) {
5939 case XPATH_UNDEFINED:
5940#ifdef DEGUB_EXPR
5941 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5942#endif
5943 ret = xmlXPathNAN;
5944 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005945 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005946 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005947 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5948 break;
5949 case XPATH_STRING:
5950 ret = xmlXPathCastStringToNumber(val->stringval);
5951 break;
5952 case XPATH_NUMBER:
5953 ret = val->floatval;
5954 break;
5955 case XPATH_BOOLEAN:
5956 ret = xmlXPathCastBooleanToNumber(val->boolval);
5957 break;
5958 case XPATH_USERS:
5959 case XPATH_POINT:
5960 case XPATH_RANGE:
5961 case XPATH_LOCATIONSET:
5962 TODO;
5963 ret = xmlXPathNAN;
5964 break;
5965 }
5966 return(ret);
5967}
5968
5969/**
5970 * xmlXPathConvertNumber:
5971 * @val: an XPath object
5972 *
5973 * Converts an existing object to its number() equivalent
5974 *
5975 * Returns the new object, the old one is freed (or the operation
5976 * is done directly on @val)
5977 */
5978xmlXPathObjectPtr
5979xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5980 xmlXPathObjectPtr ret;
5981
5982 if (val == NULL)
5983 return(xmlXPathNewFloat(0.0));
5984 if (val->type == XPATH_NUMBER)
5985 return(val);
5986 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5987 xmlXPathFreeObject(val);
5988 return(ret);
5989}
5990
5991/**
5992 * xmlXPathCastNumberToBoolean:
5993 * @val: a number
5994 *
5995 * Converts a number to its boolean value
5996 *
5997 * Returns the boolean value
5998 */
5999int
6000xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00006001 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006002 return(0);
6003 return(1);
6004}
6005
6006/**
6007 * xmlXPathCastStringToBoolean:
6008 * @val: a string
6009 *
6010 * Converts a string to its boolean value
6011 *
6012 * Returns the boolean value
6013 */
6014int
6015xmlXPathCastStringToBoolean (const xmlChar *val) {
6016 if ((val == NULL) || (xmlStrlen(val) == 0))
6017 return(0);
6018 return(1);
6019}
6020
6021/**
6022 * xmlXPathCastNodeSetToBoolean:
6023 * @ns: a node-set
6024 *
6025 * Converts a node-set to its boolean value
6026 *
6027 * Returns the boolean value
6028 */
6029int
6030xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6031 if ((ns == NULL) || (ns->nodeNr == 0))
6032 return(0);
6033 return(1);
6034}
6035
6036/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006037 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006038 * @val: an XPath object
6039 *
6040 * Converts an XPath object to its boolean value
6041 *
6042 * Returns the boolean value
6043 */
6044int
6045xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6046 int ret = 0;
6047
6048 if (val == NULL)
6049 return(0);
6050 switch (val->type) {
6051 case XPATH_UNDEFINED:
6052#ifdef DEBUG_EXPR
6053 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6054#endif
6055 ret = 0;
6056 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006057 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00006058 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006059 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6060 break;
6061 case XPATH_STRING:
6062 ret = xmlXPathCastStringToBoolean(val->stringval);
6063 break;
6064 case XPATH_NUMBER:
6065 ret = xmlXPathCastNumberToBoolean(val->floatval);
6066 break;
6067 case XPATH_BOOLEAN:
6068 ret = val->boolval;
6069 break;
6070 case XPATH_USERS:
6071 case XPATH_POINT:
6072 case XPATH_RANGE:
6073 case XPATH_LOCATIONSET:
6074 TODO;
6075 ret = 0;
6076 break;
6077 }
6078 return(ret);
6079}
6080
6081
6082/**
6083 * xmlXPathConvertBoolean:
6084 * @val: an XPath object
6085 *
6086 * Converts an existing object to its boolean() equivalent
6087 *
6088 * Returns the new object, the old one is freed (or the operation
6089 * is done directly on @val)
6090 */
6091xmlXPathObjectPtr
6092xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6093 xmlXPathObjectPtr ret;
6094
6095 if (val == NULL)
6096 return(xmlXPathNewBoolean(0));
6097 if (val->type == XPATH_BOOLEAN)
6098 return(val);
6099 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6100 xmlXPathFreeObject(val);
6101 return(ret);
6102}
6103
Owen Taylor3473f882001-02-23 17:55:21 +00006104/************************************************************************
6105 * *
6106 * Routines to handle XPath contexts *
6107 * *
6108 ************************************************************************/
6109
6110/**
6111 * xmlXPathNewContext:
6112 * @doc: the XML document
6113 *
6114 * Create a new xmlXPathContext
6115 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006116 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006117 */
6118xmlXPathContextPtr
6119xmlXPathNewContext(xmlDocPtr doc) {
6120 xmlXPathContextPtr ret;
6121
6122 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6123 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006124 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006125 return(NULL);
6126 }
6127 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6128 ret->doc = doc;
6129 ret->node = NULL;
6130
6131 ret->varHash = NULL;
6132
6133 ret->nb_types = 0;
6134 ret->max_types = 0;
6135 ret->types = NULL;
6136
6137 ret->funcHash = xmlHashCreate(0);
6138
6139 ret->nb_axis = 0;
6140 ret->max_axis = 0;
6141 ret->axis = NULL;
6142
6143 ret->nsHash = NULL;
6144 ret->user = NULL;
6145
6146 ret->contextSize = -1;
6147 ret->proximityPosition = -1;
6148
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006149#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006150 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006151 xmlXPathFreeContext(ret);
6152 return(NULL);
6153 }
6154#endif
6155
Daniel Veillard45490ae2008-07-29 09:13:19 +00006156 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006157
Owen Taylor3473f882001-02-23 17:55:21 +00006158 return(ret);
6159}
6160
6161/**
6162 * xmlXPathFreeContext:
6163 * @ctxt: the context to free
6164 *
6165 * Free up an xmlXPathContext
6166 */
6167void
6168xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006169 if (ctxt == NULL) return;
6170
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006171 if (ctxt->cache != NULL)
6172 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006173 xmlXPathRegisteredNsCleanup(ctxt);
6174 xmlXPathRegisteredFuncsCleanup(ctxt);
6175 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006176 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006177 xmlFree(ctxt);
6178}
6179
6180/************************************************************************
6181 * *
6182 * Routines to handle XPath parser contexts *
6183 * *
6184 ************************************************************************/
6185
6186#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006187 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006188 __xmlRaiseError(NULL, NULL, NULL, \
6189 NULL, NULL, XML_FROM_XPATH, \
6190 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6191 __FILE__, __LINE__, \
6192 NULL, NULL, NULL, 0, 0, \
6193 "NULL context pointer\n"); \
6194 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006195 } \
6196
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006197#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006198 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006199 __xmlRaiseError(NULL, NULL, NULL, \
6200 NULL, NULL, XML_FROM_XPATH, \
6201 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6202 __FILE__, __LINE__, \
6203 NULL, NULL, NULL, 0, 0, \
6204 "NULL context pointer\n"); \
6205 return(-1); \
6206 } \
6207
Owen Taylor3473f882001-02-23 17:55:21 +00006208
6209#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006210 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006211 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006212 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006213 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006214 }
Owen Taylor3473f882001-02-23 17:55:21 +00006215
6216
6217/**
6218 * xmlXPathNewParserContext:
6219 * @str: the XPath expression
6220 * @ctxt: the XPath context
6221 *
6222 * Create a new xmlXPathParserContext
6223 *
6224 * Returns the xmlXPathParserContext just allocated.
6225 */
6226xmlXPathParserContextPtr
6227xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6228 xmlXPathParserContextPtr ret;
6229
6230 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6231 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006232 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006233 return(NULL);
6234 }
6235 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6236 ret->cur = ret->base = str;
6237 ret->context = ctxt;
6238
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006239 ret->comp = xmlXPathNewCompExpr();
6240 if (ret->comp == NULL) {
6241 xmlFree(ret->valueTab);
6242 xmlFree(ret);
6243 return(NULL);
6244 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006245 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6246 ret->comp->dict = ctxt->dict;
6247 xmlDictReference(ret->comp->dict);
6248 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006249
6250 return(ret);
6251}
6252
6253/**
6254 * xmlXPathCompParserContext:
6255 * @comp: the XPath compiled expression
6256 * @ctxt: the XPath context
6257 *
6258 * Create a new xmlXPathParserContext when processing a compiled expression
6259 *
6260 * Returns the xmlXPathParserContext just allocated.
6261 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006262static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006263xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6264 xmlXPathParserContextPtr ret;
6265
6266 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6267 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006268 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006269 return(NULL);
6270 }
6271 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6272
Owen Taylor3473f882001-02-23 17:55:21 +00006273 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006274 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006275 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006276 if (ret->valueTab == NULL) {
6277 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006278 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006279 return(NULL);
6280 }
Owen Taylor3473f882001-02-23 17:55:21 +00006281 ret->valueNr = 0;
6282 ret->valueMax = 10;
6283 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006284 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006285
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006286 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006287 ret->comp = comp;
6288
Owen Taylor3473f882001-02-23 17:55:21 +00006289 return(ret);
6290}
6291
6292/**
6293 * xmlXPathFreeParserContext:
6294 * @ctxt: the context to free
6295 *
6296 * Free up an xmlXPathParserContext
6297 */
6298void
6299xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006300 int i;
6301
Owen Taylor3473f882001-02-23 17:55:21 +00006302 if (ctxt->valueTab != NULL) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006303 for (i = 0; i < ctxt->valueNr; i++) {
6304 if (ctxt->context)
6305 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6306 else
6307 xmlXPathFreeObject(ctxt->valueTab[i]);
6308 }
Owen Taylor3473f882001-02-23 17:55:21 +00006309 xmlFree(ctxt->valueTab);
6310 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006311 if (ctxt->comp != NULL) {
6312#ifdef XPATH_STREAMING
6313 if (ctxt->comp->stream != NULL) {
6314 xmlFreePatternList(ctxt->comp->stream);
6315 ctxt->comp->stream = NULL;
6316 }
6317#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006318 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006319 }
Owen Taylor3473f882001-02-23 17:55:21 +00006320 xmlFree(ctxt);
6321}
6322
6323/************************************************************************
6324 * *
6325 * The implicit core function library *
6326 * *
6327 ************************************************************************/
6328
Owen Taylor3473f882001-02-23 17:55:21 +00006329/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006330 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006331 * @node: a node pointer
6332 *
6333 * Function computing the beginning of the string value of the node,
6334 * used to speed up comparisons
6335 *
6336 * Returns an int usable as a hash
6337 */
6338static unsigned int
6339xmlXPathNodeValHash(xmlNodePtr node) {
6340 int len = 2;
6341 const xmlChar * string = NULL;
6342 xmlNodePtr tmp = NULL;
6343 unsigned int ret = 0;
6344
6345 if (node == NULL)
6346 return(0);
6347
Daniel Veillard9adc0462003-03-24 18:39:54 +00006348 if (node->type == XML_DOCUMENT_NODE) {
6349 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6350 if (tmp == NULL)
6351 node = node->children;
6352 else
6353 node = tmp;
6354
6355 if (node == NULL)
6356 return(0);
6357 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006358
6359 switch (node->type) {
6360 case XML_COMMENT_NODE:
6361 case XML_PI_NODE:
6362 case XML_CDATA_SECTION_NODE:
6363 case XML_TEXT_NODE:
6364 string = node->content;
6365 if (string == NULL)
6366 return(0);
6367 if (string[0] == 0)
6368 return(0);
6369 return(((unsigned int) string[0]) +
6370 (((unsigned int) string[1]) << 8));
6371 case XML_NAMESPACE_DECL:
6372 string = ((xmlNsPtr)node)->href;
6373 if (string == NULL)
6374 return(0);
6375 if (string[0] == 0)
6376 return(0);
6377 return(((unsigned int) string[0]) +
6378 (((unsigned int) string[1]) << 8));
6379 case XML_ATTRIBUTE_NODE:
6380 tmp = ((xmlAttrPtr) node)->children;
6381 break;
6382 case XML_ELEMENT_NODE:
6383 tmp = node->children;
6384 break;
6385 default:
6386 return(0);
6387 }
6388 while (tmp != NULL) {
6389 switch (tmp->type) {
6390 case XML_COMMENT_NODE:
6391 case XML_PI_NODE:
6392 case XML_CDATA_SECTION_NODE:
6393 case XML_TEXT_NODE:
6394 string = tmp->content;
6395 break;
6396 case XML_NAMESPACE_DECL:
6397 string = ((xmlNsPtr)tmp)->href;
6398 break;
6399 default:
6400 break;
6401 }
6402 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006403 if (len == 1) {
6404 return(ret + (((unsigned int) string[0]) << 8));
6405 }
6406 if (string[1] == 0) {
6407 len = 1;
6408 ret = (unsigned int) string[0];
6409 } else {
6410 return(((unsigned int) string[0]) +
6411 (((unsigned int) string[1]) << 8));
6412 }
6413 }
6414 /*
6415 * Skip to next node
6416 */
6417 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6418 if (tmp->children->type != XML_ENTITY_DECL) {
6419 tmp = tmp->children;
6420 continue;
6421 }
6422 }
6423 if (tmp == node)
6424 break;
6425
6426 if (tmp->next != NULL) {
6427 tmp = tmp->next;
6428 continue;
6429 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006430
Daniel Veillardf06307e2001-07-03 10:35:50 +00006431 do {
6432 tmp = tmp->parent;
6433 if (tmp == NULL)
6434 break;
6435 if (tmp == node) {
6436 tmp = NULL;
6437 break;
6438 }
6439 if (tmp->next != NULL) {
6440 tmp = tmp->next;
6441 break;
6442 }
6443 } while (tmp != NULL);
6444 }
6445 return(ret);
6446}
6447
6448/**
6449 * xmlXPathStringHash:
6450 * @string: a string
6451 *
6452 * Function computing the beginning of the string value of the node,
6453 * used to speed up comparisons
6454 *
6455 * Returns an int usable as a hash
6456 */
6457static unsigned int
6458xmlXPathStringHash(const xmlChar * string) {
6459 if (string == NULL)
6460 return((unsigned int) 0);
6461 if (string[0] == 0)
6462 return(0);
6463 return(((unsigned int) string[0]) +
6464 (((unsigned int) string[1]) << 8));
6465}
6466
6467/**
Owen Taylor3473f882001-02-23 17:55:21 +00006468 * xmlXPathCompareNodeSetFloat:
6469 * @ctxt: the XPath Parser context
6470 * @inf: less than (1) or greater than (0)
6471 * @strict: is the comparison strict
6472 * @arg: the node set
6473 * @f: the value
6474 *
6475 * Implement the compare operation between a nodeset and a number
6476 * @ns < @val (1, 1, ...
6477 * @ns <= @val (1, 0, ...
6478 * @ns > @val (0, 1, ...
6479 * @ns >= @val (0, 0, ...
6480 *
6481 * If one object to be compared is a node-set and the other is a number,
6482 * then the comparison will be true if and only if there is a node in the
6483 * node-set such that the result of performing the comparison on the number
6484 * to be compared and on the result of converting the string-value of that
6485 * node to a number using the number function is true.
6486 *
6487 * Returns 0 or 1 depending on the results of the test.
6488 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006489static int
Owen Taylor3473f882001-02-23 17:55:21 +00006490xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6491 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6492 int i, ret = 0;
6493 xmlNodeSetPtr ns;
6494 xmlChar *str2;
6495
6496 if ((f == NULL) || (arg == NULL) ||
6497 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006498 xmlXPathReleaseObject(ctxt->context, arg);
6499 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006500 return(0);
6501 }
6502 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006503 if (ns != NULL) {
6504 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006505 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006506 if (str2 != NULL) {
6507 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006508 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006509 xmlFree(str2);
6510 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006511 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006512 ret = xmlXPathCompareValues(ctxt, inf, strict);
6513 if (ret)
6514 break;
6515 }
6516 }
Owen Taylor3473f882001-02-23 17:55:21 +00006517 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006518 xmlXPathReleaseObject(ctxt->context, arg);
6519 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006520 return(ret);
6521}
6522
6523/**
6524 * xmlXPathCompareNodeSetString:
6525 * @ctxt: the XPath Parser context
6526 * @inf: less than (1) or greater than (0)
6527 * @strict: is the comparison strict
6528 * @arg: the node set
6529 * @s: the value
6530 *
6531 * Implement the compare operation between a nodeset and a string
6532 * @ns < @val (1, 1, ...
6533 * @ns <= @val (1, 0, ...
6534 * @ns > @val (0, 1, ...
6535 * @ns >= @val (0, 0, ...
6536 *
6537 * If one object to be compared is a node-set and the other is a string,
6538 * then the comparison will be true if and only if there is a node in
6539 * the node-set such that the result of performing the comparison on the
6540 * string-value of the node and the other string is true.
6541 *
6542 * Returns 0 or 1 depending on the results of the test.
6543 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006544static int
Owen Taylor3473f882001-02-23 17:55:21 +00006545xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6546 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6547 int i, ret = 0;
6548 xmlNodeSetPtr ns;
6549 xmlChar *str2;
6550
6551 if ((s == NULL) || (arg == NULL) ||
6552 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006553 xmlXPathReleaseObject(ctxt->context, arg);
6554 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006555 return(0);
6556 }
6557 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006558 if (ns != NULL) {
6559 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006560 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006561 if (str2 != NULL) {
6562 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006563 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006564 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006565 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006566 ret = xmlXPathCompareValues(ctxt, inf, strict);
6567 if (ret)
6568 break;
6569 }
6570 }
Owen Taylor3473f882001-02-23 17:55:21 +00006571 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006572 xmlXPathReleaseObject(ctxt->context, arg);
6573 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006574 return(ret);
6575}
6576
6577/**
6578 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006579 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006580 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006581 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006582 * @arg2: the second node set object
6583 *
6584 * Implement the compare operation on nodesets:
6585 *
6586 * If both objects to be compared are node-sets, then the comparison
6587 * will be true if and only if there is a node in the first node-set
6588 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006589 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006590 * ....
6591 * When neither object to be compared is a node-set and the operator
6592 * is <=, <, >= or >, then the objects are compared by converting both
6593 * objects to numbers and comparing the numbers according to IEEE 754.
6594 * ....
6595 * The number function converts its argument to a number as follows:
6596 * - a string that consists of optional whitespace followed by an
6597 * optional minus sign followed by a Number followed by whitespace
6598 * is converted to the IEEE 754 number that is nearest (according
6599 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6600 * represented by the string; any other string is converted to NaN
6601 *
6602 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006603 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006604 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006605static int
6606xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006607 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6608 int i, j, init = 0;
6609 double val1;
6610 double *values2;
6611 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006612 xmlNodeSetPtr ns1;
6613 xmlNodeSetPtr ns2;
6614
6615 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006616 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6617 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006618 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006619 }
Owen Taylor3473f882001-02-23 17:55:21 +00006620 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006621 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6622 xmlXPathFreeObject(arg1);
6623 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006624 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006625 }
Owen Taylor3473f882001-02-23 17:55:21 +00006626
6627 ns1 = arg1->nodesetval;
6628 ns2 = arg2->nodesetval;
6629
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006630 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006631 xmlXPathFreeObject(arg1);
6632 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006633 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006634 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006635 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006636 xmlXPathFreeObject(arg1);
6637 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006638 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006639 }
Owen Taylor3473f882001-02-23 17:55:21 +00006640
6641 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6642 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006643 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006644 xmlXPathFreeObject(arg1);
6645 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006646 return(0);
6647 }
6648 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006649 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006650 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006651 continue;
6652 for (j = 0;j < ns2->nodeNr;j++) {
6653 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006654 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006655 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006656 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006657 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006658 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006659 ret = (val1 < values2[j]);
6660 else if (inf && !strict)
6661 ret = (val1 <= values2[j]);
6662 else if (!inf && strict)
6663 ret = (val1 > values2[j]);
6664 else if (!inf && !strict)
6665 ret = (val1 >= values2[j]);
6666 if (ret)
6667 break;
6668 }
6669 if (ret)
6670 break;
6671 init = 1;
6672 }
6673 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006674 xmlXPathFreeObject(arg1);
6675 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006676 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006677}
6678
6679/**
6680 * xmlXPathCompareNodeSetValue:
6681 * @ctxt: the XPath Parser context
6682 * @inf: less than (1) or greater than (0)
6683 * @strict: is the comparison strict
6684 * @arg: the node set
6685 * @val: the value
6686 *
6687 * Implement the compare operation between a nodeset and a value
6688 * @ns < @val (1, 1, ...
6689 * @ns <= @val (1, 0, ...
6690 * @ns > @val (0, 1, ...
6691 * @ns >= @val (0, 0, ...
6692 *
6693 * If one object to be compared is a node-set and the other is a boolean,
6694 * then the comparison will be true if and only if the result of performing
6695 * the comparison on the boolean and on the result of converting
6696 * the node-set to a boolean using the boolean function is true.
6697 *
6698 * Returns 0 or 1 depending on the results of the test.
6699 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006700static int
Owen Taylor3473f882001-02-23 17:55:21 +00006701xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6702 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6703 if ((val == NULL) || (arg == NULL) ||
6704 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6705 return(0);
6706
6707 switch(val->type) {
6708 case XPATH_NUMBER:
6709 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6710 case XPATH_NODESET:
6711 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006712 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006713 case XPATH_STRING:
6714 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6715 case XPATH_BOOLEAN:
6716 valuePush(ctxt, arg);
6717 xmlXPathBooleanFunction(ctxt, 1);
6718 valuePush(ctxt, val);
6719 return(xmlXPathCompareValues(ctxt, inf, strict));
6720 default:
Nick Wellnhofercf60dbe2017-05-25 16:20:56 +02006721 xmlGenericError(xmlGenericErrorContext,
6722 "xmlXPathCompareNodeSetValue: Can't compare node set "
6723 "and object of type %d\n",
6724 val->type);
6725 xmlXPathReleaseObject(ctxt->context, arg);
6726 xmlXPathReleaseObject(ctxt->context, val);
6727 XP_ERROR0(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006728 }
6729 return(0);
6730}
6731
6732/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006733 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006734 * @arg: the nodeset object argument
6735 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006736 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006737 *
6738 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6739 * If one object to be compared is a node-set and the other is a string,
6740 * then the comparison will be true if and only if there is a node in
6741 * the node-set such that the result of performing the comparison on the
6742 * string-value of the node and the other string is true.
6743 *
6744 * Returns 0 or 1 depending on the results of the test.
6745 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006746static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006747xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006748{
Owen Taylor3473f882001-02-23 17:55:21 +00006749 int i;
6750 xmlNodeSetPtr ns;
6751 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006752 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006753
6754 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006755 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6756 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006757 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006758 /*
6759 * A NULL nodeset compared with a string is always false
6760 * (since there is no node equal, and no node not equal)
6761 */
6762 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006763 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006764 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006765 for (i = 0; i < ns->nodeNr; i++) {
6766 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6767 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6768 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6769 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006770 if (neq)
6771 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006772 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006773 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6774 if (neq)
6775 continue;
6776 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006777 } else if (neq) {
6778 if (str2 != NULL)
6779 xmlFree(str2);
6780 return (1);
6781 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006782 if (str2 != NULL)
6783 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006784 } else if (neq)
6785 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006786 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006787 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006788}
6789
6790/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006791 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006792 * @arg: the nodeset object argument
6793 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006794 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006795 *
6796 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6797 * If one object to be compared is a node-set and the other is a number,
6798 * then the comparison will be true if and only if there is a node in
6799 * the node-set such that the result of performing the comparison on the
6800 * number to be compared and on the result of converting the string-value
6801 * of that node to a number using the number function is true.
6802 *
6803 * Returns 0 or 1 depending on the results of the test.
6804 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006805static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006806xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6807 xmlXPathObjectPtr arg, double f, int neq) {
6808 int i, ret=0;
6809 xmlNodeSetPtr ns;
6810 xmlChar *str2;
6811 xmlXPathObjectPtr val;
6812 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006813
6814 if ((arg == NULL) ||
6815 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6816 return(0);
6817
William M. Brack0c022ad2002-07-12 00:56:01 +00006818 ns = arg->nodesetval;
6819 if (ns != NULL) {
6820 for (i=0;i<ns->nodeNr;i++) {
6821 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6822 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006823 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006824 xmlFree(str2);
6825 xmlXPathNumberFunction(ctxt, 1);
6826 val = valuePop(ctxt);
6827 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006828 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006829 if (!xmlXPathIsNaN(v)) {
6830 if ((!neq) && (v==f)) {
6831 ret = 1;
6832 break;
6833 } else if ((neq) && (v!=f)) {
6834 ret = 1;
6835 break;
6836 }
William M. Brack32f0f712005-07-14 07:00:33 +00006837 } else { /* NaN is unequal to any value */
6838 if (neq)
6839 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006840 }
6841 }
6842 }
6843 }
6844
6845 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006846}
6847
6848
6849/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006850 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006851 * @arg1: first nodeset object argument
6852 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006853 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006854 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006855 * Implement the equal / not equal operation on XPath nodesets:
6856 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006857 * If both objects to be compared are node-sets, then the comparison
6858 * will be true if and only if there is a node in the first node-set and
6859 * a node in the second node-set such that the result of performing the
6860 * comparison on the string-values of the two nodes is true.
6861 *
6862 * (needless to say, this is a costly operation)
6863 *
6864 * Returns 0 or 1 depending on the results of the test.
6865 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006866static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006867xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006868 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006869 unsigned int *hashs1;
6870 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006871 xmlChar **values1;
6872 xmlChar **values2;
6873 int ret = 0;
6874 xmlNodeSetPtr ns1;
6875 xmlNodeSetPtr ns2;
6876
6877 if ((arg1 == NULL) ||
6878 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6879 return(0);
6880 if ((arg2 == NULL) ||
6881 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6882 return(0);
6883
6884 ns1 = arg1->nodesetval;
6885 ns2 = arg2->nodesetval;
6886
Daniel Veillard911f49a2001-04-07 15:39:35 +00006887 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006888 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006889 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006890 return(0);
6891
6892 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006893 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006894 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006895 if (neq == 0)
6896 for (i = 0;i < ns1->nodeNr;i++)
6897 for (j = 0;j < ns2->nodeNr;j++)
6898 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6899 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006900
6901 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006902 if (values1 == NULL) {
6903 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006904 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006905 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006906 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6907 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006908 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006909 xmlFree(values1);
6910 return(0);
6911 }
Owen Taylor3473f882001-02-23 17:55:21 +00006912 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6913 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6914 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006915 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006916 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006917 xmlFree(values1);
6918 return(0);
6919 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006920 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6921 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006922 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006923 xmlFree(hashs1);
6924 xmlFree(values1);
6925 xmlFree(values2);
6926 return(0);
6927 }
Owen Taylor3473f882001-02-23 17:55:21 +00006928 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6929 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006930 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006931 for (j = 0;j < ns2->nodeNr;j++) {
6932 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006933 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006934 if (hashs1[i] != hashs2[j]) {
6935 if (neq) {
6936 ret = 1;
6937 break;
6938 }
6939 }
6940 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006941 if (values1[i] == NULL)
6942 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6943 if (values2[j] == NULL)
6944 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006945 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006946 if (ret)
6947 break;
6948 }
Owen Taylor3473f882001-02-23 17:55:21 +00006949 }
6950 if (ret)
6951 break;
6952 }
6953 for (i = 0;i < ns1->nodeNr;i++)
6954 if (values1[i] != NULL)
6955 xmlFree(values1[i]);
6956 for (j = 0;j < ns2->nodeNr;j++)
6957 if (values2[j] != NULL)
6958 xmlFree(values2[j]);
6959 xmlFree(values1);
6960 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006961 xmlFree(hashs1);
6962 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006963 return(ret);
6964}
6965
William M. Brack0c022ad2002-07-12 00:56:01 +00006966static int
6967xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6968 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006969 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006970 /*
6971 *At this point we are assured neither arg1 nor arg2
6972 *is a nodeset, so we can just pick the appropriate routine.
6973 */
Owen Taylor3473f882001-02-23 17:55:21 +00006974 switch (arg1->type) {
6975 case XPATH_UNDEFINED:
6976#ifdef DEBUG_EXPR
6977 xmlGenericError(xmlGenericErrorContext,
6978 "Equal: undefined\n");
6979#endif
6980 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006981 case XPATH_BOOLEAN:
6982 switch (arg2->type) {
6983 case XPATH_UNDEFINED:
6984#ifdef DEBUG_EXPR
6985 xmlGenericError(xmlGenericErrorContext,
6986 "Equal: undefined\n");
6987#endif
6988 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006989 case XPATH_BOOLEAN:
6990#ifdef DEBUG_EXPR
6991 xmlGenericError(xmlGenericErrorContext,
6992 "Equal: %d boolean %d \n",
6993 arg1->boolval, arg2->boolval);
6994#endif
6995 ret = (arg1->boolval == arg2->boolval);
6996 break;
6997 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006998 ret = (arg1->boolval ==
6999 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007000 break;
7001 case XPATH_STRING:
7002 if ((arg2->stringval == NULL) ||
7003 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007004 else
Owen Taylor3473f882001-02-23 17:55:21 +00007005 ret = 1;
7006 ret = (arg1->boolval == ret);
7007 break;
7008 case XPATH_USERS:
7009 case XPATH_POINT:
7010 case XPATH_RANGE:
7011 case XPATH_LOCATIONSET:
7012 TODO
7013 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007014 case XPATH_NODESET:
7015 case XPATH_XSLT_TREE:
7016 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007017 }
7018 break;
7019 case XPATH_NUMBER:
7020 switch (arg2->type) {
7021 case XPATH_UNDEFINED:
7022#ifdef DEBUG_EXPR
7023 xmlGenericError(xmlGenericErrorContext,
7024 "Equal: undefined\n");
7025#endif
7026 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007027 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00007028 ret = (arg2->boolval==
7029 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007030 break;
7031 case XPATH_STRING:
7032 valuePush(ctxt, arg2);
7033 xmlXPathNumberFunction(ctxt, 1);
7034 arg2 = valuePop(ctxt);
7035 /* no break on purpose */
7036 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007037 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007038 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007039 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007040 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007041 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7042 if (xmlXPathIsInf(arg2->floatval) == 1)
7043 ret = 1;
7044 else
7045 ret = 0;
7046 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7047 if (xmlXPathIsInf(arg2->floatval) == -1)
7048 ret = 1;
7049 else
7050 ret = 0;
7051 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7052 if (xmlXPathIsInf(arg1->floatval) == 1)
7053 ret = 1;
7054 else
7055 ret = 0;
7056 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7057 if (xmlXPathIsInf(arg1->floatval) == -1)
7058 ret = 1;
7059 else
7060 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007061 } else {
7062 ret = (arg1->floatval == arg2->floatval);
7063 }
Owen Taylor3473f882001-02-23 17:55:21 +00007064 break;
7065 case XPATH_USERS:
7066 case XPATH_POINT:
7067 case XPATH_RANGE:
7068 case XPATH_LOCATIONSET:
7069 TODO
7070 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007071 case XPATH_NODESET:
7072 case XPATH_XSLT_TREE:
7073 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007074 }
7075 break;
7076 case XPATH_STRING:
7077 switch (arg2->type) {
7078 case XPATH_UNDEFINED:
7079#ifdef DEBUG_EXPR
7080 xmlGenericError(xmlGenericErrorContext,
7081 "Equal: undefined\n");
7082#endif
7083 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007084 case XPATH_BOOLEAN:
7085 if ((arg1->stringval == NULL) ||
7086 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007087 else
Owen Taylor3473f882001-02-23 17:55:21 +00007088 ret = 1;
7089 ret = (arg2->boolval == ret);
7090 break;
7091 case XPATH_STRING:
7092 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7093 break;
7094 case XPATH_NUMBER:
7095 valuePush(ctxt, arg1);
7096 xmlXPathNumberFunction(ctxt, 1);
7097 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007098 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007099 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007100 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007101 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007102 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7103 if (xmlXPathIsInf(arg2->floatval) == 1)
7104 ret = 1;
7105 else
7106 ret = 0;
7107 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7108 if (xmlXPathIsInf(arg2->floatval) == -1)
7109 ret = 1;
7110 else
7111 ret = 0;
7112 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7113 if (xmlXPathIsInf(arg1->floatval) == 1)
7114 ret = 1;
7115 else
7116 ret = 0;
7117 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7118 if (xmlXPathIsInf(arg1->floatval) == -1)
7119 ret = 1;
7120 else
7121 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007122 } else {
7123 ret = (arg1->floatval == arg2->floatval);
7124 }
Owen Taylor3473f882001-02-23 17:55:21 +00007125 break;
7126 case XPATH_USERS:
7127 case XPATH_POINT:
7128 case XPATH_RANGE:
7129 case XPATH_LOCATIONSET:
7130 TODO
7131 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007132 case XPATH_NODESET:
7133 case XPATH_XSLT_TREE:
7134 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007135 }
7136 break;
7137 case XPATH_USERS:
7138 case XPATH_POINT:
7139 case XPATH_RANGE:
7140 case XPATH_LOCATIONSET:
7141 TODO
7142 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007143 case XPATH_NODESET:
7144 case XPATH_XSLT_TREE:
7145 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007146 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007147 xmlXPathReleaseObject(ctxt->context, arg1);
7148 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007149 return(ret);
7150}
7151
William M. Brack0c022ad2002-07-12 00:56:01 +00007152/**
7153 * xmlXPathEqualValues:
7154 * @ctxt: the XPath Parser context
7155 *
7156 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7157 *
7158 * Returns 0 or 1 depending on the results of the test.
7159 */
7160int
7161xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7162 xmlXPathObjectPtr arg1, arg2, argtmp;
7163 int ret = 0;
7164
Daniel Veillard6128c012004-11-08 17:16:15 +00007165 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007166 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007167 arg1 = valuePop(ctxt);
7168 if ((arg1 == NULL) || (arg2 == NULL)) {
7169 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007170 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007171 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007172 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007173 XP_ERROR0(XPATH_INVALID_OPERAND);
7174 }
7175
7176 if (arg1 == arg2) {
7177#ifdef DEBUG_EXPR
7178 xmlGenericError(xmlGenericErrorContext,
7179 "Equal: by pointer\n");
7180#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007181 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007182 return(1);
7183 }
7184
7185 /*
7186 *If either argument is a nodeset, it's a 'special case'
7187 */
7188 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7189 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7190 /*
7191 *Hack it to assure arg1 is the nodeset
7192 */
7193 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7194 argtmp = arg2;
7195 arg2 = arg1;
7196 arg1 = argtmp;
7197 }
7198 switch (arg2->type) {
7199 case XPATH_UNDEFINED:
7200#ifdef DEBUG_EXPR
7201 xmlGenericError(xmlGenericErrorContext,
7202 "Equal: undefined\n");
7203#endif
7204 break;
7205 case XPATH_NODESET:
7206 case XPATH_XSLT_TREE:
7207 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7208 break;
7209 case XPATH_BOOLEAN:
7210 if ((arg1->nodesetval == NULL) ||
7211 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007212 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007213 ret = 1;
7214 ret = (ret == arg2->boolval);
7215 break;
7216 case XPATH_NUMBER:
7217 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7218 break;
7219 case XPATH_STRING:
7220 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7221 break;
7222 case XPATH_USERS:
7223 case XPATH_POINT:
7224 case XPATH_RANGE:
7225 case XPATH_LOCATIONSET:
7226 TODO
7227 break;
7228 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007229 xmlXPathReleaseObject(ctxt->context, arg1);
7230 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007231 return(ret);
7232 }
7233
7234 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7235}
7236
7237/**
7238 * xmlXPathNotEqualValues:
7239 * @ctxt: the XPath Parser context
7240 *
7241 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7242 *
7243 * Returns 0 or 1 depending on the results of the test.
7244 */
7245int
7246xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7247 xmlXPathObjectPtr arg1, arg2, argtmp;
7248 int ret = 0;
7249
Daniel Veillard6128c012004-11-08 17:16:15 +00007250 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007251 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007252 arg1 = valuePop(ctxt);
7253 if ((arg1 == NULL) || (arg2 == NULL)) {
7254 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007255 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007256 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007257 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007258 XP_ERROR0(XPATH_INVALID_OPERAND);
7259 }
7260
7261 if (arg1 == arg2) {
7262#ifdef DEBUG_EXPR
7263 xmlGenericError(xmlGenericErrorContext,
7264 "NotEqual: by pointer\n");
7265#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007266 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007267 return(0);
7268 }
7269
7270 /*
7271 *If either argument is a nodeset, it's a 'special case'
7272 */
7273 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7274 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7275 /*
7276 *Hack it to assure arg1 is the nodeset
7277 */
7278 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7279 argtmp = arg2;
7280 arg2 = arg1;
7281 arg1 = argtmp;
7282 }
7283 switch (arg2->type) {
7284 case XPATH_UNDEFINED:
7285#ifdef DEBUG_EXPR
7286 xmlGenericError(xmlGenericErrorContext,
7287 "NotEqual: undefined\n");
7288#endif
7289 break;
7290 case XPATH_NODESET:
7291 case XPATH_XSLT_TREE:
7292 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7293 break;
7294 case XPATH_BOOLEAN:
7295 if ((arg1->nodesetval == NULL) ||
7296 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007297 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007298 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007299 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007300 break;
7301 case XPATH_NUMBER:
7302 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7303 break;
7304 case XPATH_STRING:
7305 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7306 break;
7307 case XPATH_USERS:
7308 case XPATH_POINT:
7309 case XPATH_RANGE:
7310 case XPATH_LOCATIONSET:
7311 TODO
7312 break;
7313 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007314 xmlXPathReleaseObject(ctxt->context, arg1);
7315 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007316 return(ret);
7317 }
7318
7319 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7320}
Owen Taylor3473f882001-02-23 17:55:21 +00007321
7322/**
7323 * xmlXPathCompareValues:
7324 * @ctxt: the XPath Parser context
7325 * @inf: less than (1) or greater than (0)
7326 * @strict: is the comparison strict
7327 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007328 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007329 * @arg1 < @arg2 (1, 1, ...
7330 * @arg1 <= @arg2 (1, 0, ...
7331 * @arg1 > @arg2 (0, 1, ...
7332 * @arg1 >= @arg2 (0, 0, ...
7333 *
7334 * When neither object to be compared is a node-set and the operator is
7335 * <=, <, >=, >, then the objects are compared by converted both objects
7336 * to numbers and comparing the numbers according to IEEE 754. The <
7337 * comparison will be true if and only if the first number is less than the
7338 * second number. The <= comparison will be true if and only if the first
7339 * number is less than or equal to the second number. The > comparison
7340 * will be true if and only if the first number is greater than the second
7341 * number. The >= comparison will be true if and only if the first number
7342 * is greater than or equal to the second number.
7343 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007344 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007345 */
7346int
7347xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007348 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007349 xmlXPathObjectPtr arg1, arg2;
7350
Daniel Veillard6128c012004-11-08 17:16:15 +00007351 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007352 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007353 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007354 if ((arg1 == NULL) || (arg2 == NULL)) {
7355 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007356 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007357 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007358 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007359 XP_ERROR0(XPATH_INVALID_OPERAND);
7360 }
7361
William M. Brack0c022ad2002-07-12 00:56:01 +00007362 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7363 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007364 /*
7365 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7366 * are not freed from within this routine; they will be freed from the
7367 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7368 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007369 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7370 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007371 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007372 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007373 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007374 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7375 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007376 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007377 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7378 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007379 }
7380 }
7381 return(ret);
7382 }
7383
7384 if (arg1->type != XPATH_NUMBER) {
7385 valuePush(ctxt, arg1);
7386 xmlXPathNumberFunction(ctxt, 1);
7387 arg1 = valuePop(ctxt);
7388 }
7389 if (arg1->type != XPATH_NUMBER) {
7390 xmlXPathFreeObject(arg1);
7391 xmlXPathFreeObject(arg2);
7392 XP_ERROR0(XPATH_INVALID_OPERAND);
7393 }
7394 if (arg2->type != XPATH_NUMBER) {
7395 valuePush(ctxt, arg2);
7396 xmlXPathNumberFunction(ctxt, 1);
7397 arg2 = valuePop(ctxt);
7398 }
7399 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007400 xmlXPathReleaseObject(ctxt->context, arg1);
7401 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007402 XP_ERROR0(XPATH_INVALID_OPERAND);
7403 }
7404 /*
7405 * Add tests for infinity and nan
7406 * => feedback on 3.4 for Inf and NaN
7407 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007408 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007409 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007410 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007411 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007412 arg1i=xmlXPathIsInf(arg1->floatval);
7413 arg2i=xmlXPathIsInf(arg2->floatval);
7414 if (inf && strict) {
7415 if ((arg1i == -1 && arg2i != -1) ||
7416 (arg2i == 1 && arg1i != 1)) {
7417 ret = 1;
7418 } else if (arg1i == 0 && arg2i == 0) {
7419 ret = (arg1->floatval < arg2->floatval);
7420 } else {
7421 ret = 0;
7422 }
7423 }
7424 else if (inf && !strict) {
7425 if (arg1i == -1 || arg2i == 1) {
7426 ret = 1;
7427 } else if (arg1i == 0 && arg2i == 0) {
7428 ret = (arg1->floatval <= arg2->floatval);
7429 } else {
7430 ret = 0;
7431 }
7432 }
7433 else if (!inf && strict) {
7434 if ((arg1i == 1 && arg2i != 1) ||
7435 (arg2i == -1 && arg1i != -1)) {
7436 ret = 1;
7437 } else if (arg1i == 0 && arg2i == 0) {
7438 ret = (arg1->floatval > arg2->floatval);
7439 } else {
7440 ret = 0;
7441 }
7442 }
7443 else if (!inf && !strict) {
7444 if (arg1i == 1 || arg2i == -1) {
7445 ret = 1;
7446 } else if (arg1i == 0 && arg2i == 0) {
7447 ret = (arg1->floatval >= arg2->floatval);
7448 } else {
7449 ret = 0;
7450 }
7451 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007452 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007453 xmlXPathReleaseObject(ctxt->context, arg1);
7454 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007455 return(ret);
7456}
7457
7458/**
7459 * xmlXPathValueFlipSign:
7460 * @ctxt: the XPath Parser context
7461 *
7462 * Implement the unary - operation on an XPath object
7463 * The numeric operators convert their operands to numbers as if
7464 * by calling the number function.
7465 */
7466void
7467xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007468 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007469 CAST_TO_NUMBER;
7470 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007471 if (xmlXPathIsNaN(ctxt->value->floatval))
7472 ctxt->value->floatval=xmlXPathNAN;
7473 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7474 ctxt->value->floatval=xmlXPathNINF;
7475 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7476 ctxt->value->floatval=xmlXPathPINF;
7477 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007478 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7479 ctxt->value->floatval = xmlXPathNZERO;
7480 else
7481 ctxt->value->floatval = 0;
7482 }
7483 else
7484 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007485}
7486
7487/**
7488 * xmlXPathAddValues:
7489 * @ctxt: the XPath Parser context
7490 *
7491 * Implement the add operation on XPath objects:
7492 * The numeric operators convert their operands to numbers as if
7493 * by calling the number function.
7494 */
7495void
7496xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7497 xmlXPathObjectPtr arg;
7498 double val;
7499
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007500 arg = valuePop(ctxt);
7501 if (arg == NULL)
7502 XP_ERROR(XPATH_INVALID_OPERAND);
7503 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007504 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007505 CAST_TO_NUMBER;
7506 CHECK_TYPE(XPATH_NUMBER);
7507 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007508}
7509
7510/**
7511 * xmlXPathSubValues:
7512 * @ctxt: the XPath Parser context
7513 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007514 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007515 * The numeric operators convert their operands to numbers as if
7516 * by calling the number function.
7517 */
7518void
7519xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7520 xmlXPathObjectPtr arg;
7521 double val;
7522
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007523 arg = valuePop(ctxt);
7524 if (arg == NULL)
7525 XP_ERROR(XPATH_INVALID_OPERAND);
7526 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007527 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007528 CAST_TO_NUMBER;
7529 CHECK_TYPE(XPATH_NUMBER);
7530 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007531}
7532
7533/**
7534 * xmlXPathMultValues:
7535 * @ctxt: the XPath Parser context
7536 *
7537 * Implement the multiply operation on XPath objects:
7538 * The numeric operators convert their operands to numbers as if
7539 * by calling the number function.
7540 */
7541void
7542xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7543 xmlXPathObjectPtr arg;
7544 double val;
7545
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007546 arg = valuePop(ctxt);
7547 if (arg == NULL)
7548 XP_ERROR(XPATH_INVALID_OPERAND);
7549 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007550 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007551 CAST_TO_NUMBER;
7552 CHECK_TYPE(XPATH_NUMBER);
7553 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007554}
7555
7556/**
7557 * xmlXPathDivValues:
7558 * @ctxt: the XPath Parser context
7559 *
7560 * Implement the div operation on XPath objects @arg1 / @arg2:
7561 * The numeric operators convert their operands to numbers as if
7562 * by calling the number function.
7563 */
7564void
7565xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7566 xmlXPathObjectPtr arg;
7567 double val;
7568
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007569 arg = valuePop(ctxt);
7570 if (arg == NULL)
7571 XP_ERROR(XPATH_INVALID_OPERAND);
7572 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007573 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007574 CAST_TO_NUMBER;
7575 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007576 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7577 ctxt->value->floatval = xmlXPathNAN;
7578 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007579 if (ctxt->value->floatval == 0)
7580 ctxt->value->floatval = xmlXPathNAN;
7581 else if (ctxt->value->floatval > 0)
7582 ctxt->value->floatval = xmlXPathNINF;
7583 else if (ctxt->value->floatval < 0)
7584 ctxt->value->floatval = xmlXPathPINF;
7585 }
7586 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007587 if (ctxt->value->floatval == 0)
7588 ctxt->value->floatval = xmlXPathNAN;
7589 else if (ctxt->value->floatval > 0)
7590 ctxt->value->floatval = xmlXPathPINF;
7591 else if (ctxt->value->floatval < 0)
7592 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007593 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007594 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007595}
7596
7597/**
7598 * xmlXPathModValues:
7599 * @ctxt: the XPath Parser context
7600 *
7601 * Implement the mod operation on XPath objects: @arg1 / @arg2
7602 * The numeric operators convert their operands to numbers as if
7603 * by calling the number function.
7604 */
7605void
7606xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7607 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007608 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007609
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007610 arg = valuePop(ctxt);
7611 if (arg == NULL)
7612 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007613 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007614 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007615 CAST_TO_NUMBER;
7616 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007617 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007618 if (arg2 == 0)
7619 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007620 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007621 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007622 }
Owen Taylor3473f882001-02-23 17:55:21 +00007623}
7624
7625/************************************************************************
7626 * *
7627 * The traversal functions *
7628 * *
7629 ************************************************************************/
7630
Owen Taylor3473f882001-02-23 17:55:21 +00007631/*
7632 * A traversal function enumerates nodes along an axis.
7633 * Initially it must be called with NULL, and it indicates
7634 * termination on the axis by returning NULL.
7635 */
7636typedef xmlNodePtr (*xmlXPathTraversalFunction)
7637 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7638
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007639/*
7640 * xmlXPathTraversalFunctionExt:
7641 * A traversal function enumerates nodes along an axis.
7642 * Initially it must be called with NULL, and it indicates
7643 * termination on the axis by returning NULL.
7644 * The context node of the traversal is specified via @contextNode.
7645 */
7646typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7647 (xmlNodePtr cur, xmlNodePtr contextNode);
7648
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007649/*
7650 * xmlXPathNodeSetMergeFunction:
7651 * Used for merging node sets in xmlXPathCollectAndTest().
7652 */
7653typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7654 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7655
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007656
Owen Taylor3473f882001-02-23 17:55:21 +00007657/**
7658 * xmlXPathNextSelf:
7659 * @ctxt: the XPath Parser context
7660 * @cur: the current node in the traversal
7661 *
7662 * Traversal function for the "self" direction
7663 * The self axis contains just the context node itself
7664 *
7665 * Returns the next element following that axis
7666 */
7667xmlNodePtr
7668xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007669 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007670 if (cur == NULL)
7671 return(ctxt->context->node);
7672 return(NULL);
7673}
7674
7675/**
7676 * xmlXPathNextChild:
7677 * @ctxt: the XPath Parser context
7678 * @cur: the current node in the traversal
7679 *
7680 * Traversal function for the "child" direction
7681 * The child axis contains the children of the context node in document order.
7682 *
7683 * Returns the next element following that axis
7684 */
7685xmlNodePtr
7686xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007687 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007688 if (cur == NULL) {
7689 if (ctxt->context->node == NULL) return(NULL);
7690 switch (ctxt->context->node->type) {
7691 case XML_ELEMENT_NODE:
7692 case XML_TEXT_NODE:
7693 case XML_CDATA_SECTION_NODE:
7694 case XML_ENTITY_REF_NODE:
7695 case XML_ENTITY_NODE:
7696 case XML_PI_NODE:
7697 case XML_COMMENT_NODE:
7698 case XML_NOTATION_NODE:
7699 case XML_DTD_NODE:
7700 return(ctxt->context->node->children);
7701 case XML_DOCUMENT_NODE:
7702 case XML_DOCUMENT_TYPE_NODE:
7703 case XML_DOCUMENT_FRAG_NODE:
7704 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007705#ifdef LIBXML_DOCB_ENABLED
7706 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007707#endif
7708 return(((xmlDocPtr) ctxt->context->node)->children);
7709 case XML_ELEMENT_DECL:
7710 case XML_ATTRIBUTE_DECL:
7711 case XML_ENTITY_DECL:
7712 case XML_ATTRIBUTE_NODE:
7713 case XML_NAMESPACE_DECL:
7714 case XML_XINCLUDE_START:
7715 case XML_XINCLUDE_END:
7716 return(NULL);
7717 }
7718 return(NULL);
7719 }
7720 if ((cur->type == XML_DOCUMENT_NODE) ||
7721 (cur->type == XML_HTML_DOCUMENT_NODE))
7722 return(NULL);
7723 return(cur->next);
7724}
7725
7726/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007727 * xmlXPathNextChildElement:
7728 * @ctxt: the XPath Parser context
7729 * @cur: the current node in the traversal
7730 *
7731 * Traversal function for the "child" direction and nodes of type element.
7732 * The child axis contains the children of the context node in document order.
7733 *
7734 * Returns the next element following that axis
7735 */
7736static xmlNodePtr
7737xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7738 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7739 if (cur == NULL) {
7740 cur = ctxt->context->node;
7741 if (cur == NULL) return(NULL);
7742 /*
7743 * Get the first element child.
7744 */
7745 switch (cur->type) {
7746 case XML_ELEMENT_NODE:
7747 case XML_DOCUMENT_FRAG_NODE:
7748 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7749 case XML_ENTITY_NODE:
7750 cur = cur->children;
7751 if (cur != NULL) {
7752 if (cur->type == XML_ELEMENT_NODE)
7753 return(cur);
7754 do {
7755 cur = cur->next;
7756 } while ((cur != NULL) &&
7757 (cur->type != XML_ELEMENT_NODE));
7758 return(cur);
7759 }
7760 return(NULL);
7761 case XML_DOCUMENT_NODE:
7762 case XML_HTML_DOCUMENT_NODE:
7763#ifdef LIBXML_DOCB_ENABLED
7764 case XML_DOCB_DOCUMENT_NODE:
7765#endif
7766 return(xmlDocGetRootElement((xmlDocPtr) cur));
7767 default:
7768 return(NULL);
7769 }
7770 return(NULL);
7771 }
7772 /*
7773 * Get the next sibling element node.
7774 */
7775 switch (cur->type) {
7776 case XML_ELEMENT_NODE:
7777 case XML_TEXT_NODE:
7778 case XML_ENTITY_REF_NODE:
7779 case XML_ENTITY_NODE:
7780 case XML_CDATA_SECTION_NODE:
7781 case XML_PI_NODE:
7782 case XML_COMMENT_NODE:
7783 case XML_XINCLUDE_END:
7784 break;
7785 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7786 default:
7787 return(NULL);
7788 }
7789 if (cur->next != NULL) {
7790 if (cur->next->type == XML_ELEMENT_NODE)
7791 return(cur->next);
7792 cur = cur->next;
7793 do {
7794 cur = cur->next;
7795 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7796 return(cur);
7797 }
7798 return(NULL);
7799}
7800
Daniel Veillard76516062012-09-11 14:02:08 +08007801#if 0
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007802/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007803 * xmlXPathNextDescendantOrSelfElemParent:
7804 * @ctxt: the XPath Parser context
7805 * @cur: the current node in the traversal
7806 *
7807 * Traversal function for the "descendant-or-self" axis.
7808 * Additionally it returns only nodes which can be parents of
7809 * element nodes.
7810 *
7811 *
7812 * Returns the next element following that axis
7813 */
7814static xmlNodePtr
7815xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7816 xmlNodePtr contextNode)
7817{
7818 if (cur == NULL) {
7819 if (contextNode == NULL)
7820 return(NULL);
7821 switch (contextNode->type) {
7822 case XML_ELEMENT_NODE:
7823 case XML_XINCLUDE_START:
7824 case XML_DOCUMENT_FRAG_NODE:
7825 case XML_DOCUMENT_NODE:
7826#ifdef LIBXML_DOCB_ENABLED
7827 case XML_DOCB_DOCUMENT_NODE:
7828#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007829 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007830 return(contextNode);
7831 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007832 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007833 }
7834 return(NULL);
7835 } else {
7836 xmlNodePtr start = cur;
7837
7838 while (cur != NULL) {
7839 switch (cur->type) {
7840 case XML_ELEMENT_NODE:
7841 /* TODO: OK to have XInclude here? */
7842 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007843 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007844 if (cur != start)
7845 return(cur);
7846 if (cur->children != NULL) {
7847 cur = cur->children;
7848 continue;
7849 }
7850 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007851 /* Not sure if we need those here. */
7852 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007853#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007854 case XML_DOCB_DOCUMENT_NODE:
7855#endif
7856 case XML_HTML_DOCUMENT_NODE:
7857 if (cur != start)
7858 return(cur);
7859 return(xmlDocGetRootElement((xmlDocPtr) cur));
7860 default:
7861 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007862 }
7863
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007864next_sibling:
7865 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007866 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007867 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007868 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007869 } else {
7870 cur = cur->parent;
7871 goto next_sibling;
7872 }
7873 }
7874 }
7875 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007876}
Daniel Veillard76516062012-09-11 14:02:08 +08007877#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007878
7879/**
Owen Taylor3473f882001-02-23 17:55:21 +00007880 * xmlXPathNextDescendant:
7881 * @ctxt: the XPath Parser context
7882 * @cur: the current node in the traversal
7883 *
7884 * Traversal function for the "descendant" direction
7885 * the descendant axis contains the descendants of the context node in document
7886 * order; a descendant is a child or a child of a child and so on.
7887 *
7888 * Returns the next element following that axis
7889 */
7890xmlNodePtr
7891xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007892 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007893 if (cur == NULL) {
7894 if (ctxt->context->node == NULL)
7895 return(NULL);
7896 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7897 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7898 return(NULL);
7899
7900 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7901 return(ctxt->context->doc->children);
7902 return(ctxt->context->node->children);
7903 }
7904
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007905 if (cur->type == XML_NAMESPACE_DECL)
7906 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007907 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007908 /*
7909 * Do not descend on entities declarations
7910 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007911 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007912 cur = cur->children;
7913 /*
7914 * Skip DTDs
7915 */
7916 if (cur->type != XML_DTD_NODE)
7917 return(cur);
7918 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007919 }
7920
7921 if (cur == ctxt->context->node) return(NULL);
7922
Daniel Veillard68e9e742002-11-16 15:35:11 +00007923 while (cur->next != NULL) {
7924 cur = cur->next;
7925 if ((cur->type != XML_ENTITY_DECL) &&
7926 (cur->type != XML_DTD_NODE))
7927 return(cur);
7928 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007929
Owen Taylor3473f882001-02-23 17:55:21 +00007930 do {
7931 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007932 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007933 if (cur == ctxt->context->node) return(NULL);
7934 if (cur->next != NULL) {
7935 cur = cur->next;
7936 return(cur);
7937 }
7938 } while (cur != NULL);
7939 return(cur);
7940}
7941
7942/**
7943 * xmlXPathNextDescendantOrSelf:
7944 * @ctxt: the XPath Parser context
7945 * @cur: the current node in the traversal
7946 *
7947 * Traversal function for the "descendant-or-self" direction
7948 * the descendant-or-self axis contains the context node and the descendants
7949 * of the context node in document order; thus the context node is the first
7950 * node on the axis, and the first child of the context node is the second node
7951 * on the axis
7952 *
7953 * Returns the next element following that axis
7954 */
7955xmlNodePtr
7956xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007957 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007958 if (cur == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007959 return(ctxt->context->node);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007960
7961 if (ctxt->context->node == NULL)
7962 return(NULL);
7963 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7964 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7965 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007966
7967 return(xmlXPathNextDescendant(ctxt, cur));
7968}
7969
7970/**
7971 * xmlXPathNextParent:
7972 * @ctxt: the XPath Parser context
7973 * @cur: the current node in the traversal
7974 *
7975 * Traversal function for the "parent" direction
7976 * The parent axis contains the parent of the context node, if there is one.
7977 *
7978 * Returns the next element following that axis
7979 */
7980xmlNodePtr
7981xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007982 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007983 /*
7984 * the parent of an attribute or namespace node is the element
7985 * to which the attribute or namespace node is attached
7986 * Namespace handling !!!
7987 */
7988 if (cur == NULL) {
7989 if (ctxt->context->node == NULL) return(NULL);
7990 switch (ctxt->context->node->type) {
7991 case XML_ELEMENT_NODE:
7992 case XML_TEXT_NODE:
7993 case XML_CDATA_SECTION_NODE:
7994 case XML_ENTITY_REF_NODE:
7995 case XML_ENTITY_NODE:
7996 case XML_PI_NODE:
7997 case XML_COMMENT_NODE:
7998 case XML_NOTATION_NODE:
7999 case XML_DTD_NODE:
8000 case XML_ELEMENT_DECL:
8001 case XML_ATTRIBUTE_DECL:
8002 case XML_XINCLUDE_START:
8003 case XML_XINCLUDE_END:
8004 case XML_ENTITY_DECL:
8005 if (ctxt->context->node->parent == NULL)
8006 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008007 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008008 ((ctxt->context->node->parent->name[0] == ' ') ||
8009 (xmlStrEqual(ctxt->context->node->parent->name,
8010 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008011 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008012 return(ctxt->context->node->parent);
8013 case XML_ATTRIBUTE_NODE: {
8014 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8015
8016 return(att->parent);
8017 }
8018 case XML_DOCUMENT_NODE:
8019 case XML_DOCUMENT_TYPE_NODE:
8020 case XML_DOCUMENT_FRAG_NODE:
8021 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008022#ifdef LIBXML_DOCB_ENABLED
8023 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008024#endif
8025 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008026 case XML_NAMESPACE_DECL: {
8027 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008028
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008029 if ((ns->next != NULL) &&
8030 (ns->next->type != XML_NAMESPACE_DECL))
8031 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00008032 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008033 }
Owen Taylor3473f882001-02-23 17:55:21 +00008034 }
8035 }
8036 return(NULL);
8037}
8038
8039/**
8040 * xmlXPathNextAncestor:
8041 * @ctxt: the XPath Parser context
8042 * @cur: the current node in the traversal
8043 *
8044 * Traversal function for the "ancestor" direction
8045 * the ancestor axis contains the ancestors of the context node; the ancestors
8046 * of the context node consist of the parent of context node and the parent's
8047 * parent and so on; the nodes are ordered in reverse document order; thus the
8048 * parent is the first node on the axis, and the parent's parent is the second
8049 * node on the axis
8050 *
8051 * Returns the next element following that axis
8052 */
8053xmlNodePtr
8054xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008055 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008056 /*
8057 * the parent of an attribute or namespace node is the element
8058 * to which the attribute or namespace node is attached
8059 * !!!!!!!!!!!!!
8060 */
8061 if (cur == NULL) {
8062 if (ctxt->context->node == NULL) return(NULL);
8063 switch (ctxt->context->node->type) {
8064 case XML_ELEMENT_NODE:
8065 case XML_TEXT_NODE:
8066 case XML_CDATA_SECTION_NODE:
8067 case XML_ENTITY_REF_NODE:
8068 case XML_ENTITY_NODE:
8069 case XML_PI_NODE:
8070 case XML_COMMENT_NODE:
8071 case XML_DTD_NODE:
8072 case XML_ELEMENT_DECL:
8073 case XML_ATTRIBUTE_DECL:
8074 case XML_ENTITY_DECL:
8075 case XML_NOTATION_NODE:
8076 case XML_XINCLUDE_START:
8077 case XML_XINCLUDE_END:
8078 if (ctxt->context->node->parent == NULL)
8079 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008080 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008081 ((ctxt->context->node->parent->name[0] == ' ') ||
8082 (xmlStrEqual(ctxt->context->node->parent->name,
8083 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008084 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008085 return(ctxt->context->node->parent);
8086 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008087 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00008088
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008089 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00008090 }
8091 case XML_DOCUMENT_NODE:
8092 case XML_DOCUMENT_TYPE_NODE:
8093 case XML_DOCUMENT_FRAG_NODE:
8094 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008095#ifdef LIBXML_DOCB_ENABLED
8096 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008097#endif
8098 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008099 case XML_NAMESPACE_DECL: {
8100 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008101
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008102 if ((ns->next != NULL) &&
8103 (ns->next->type != XML_NAMESPACE_DECL))
8104 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008105 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008106 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008107 }
Owen Taylor3473f882001-02-23 17:55:21 +00008108 }
8109 return(NULL);
8110 }
8111 if (cur == ctxt->context->doc->children)
8112 return((xmlNodePtr) ctxt->context->doc);
8113 if (cur == (xmlNodePtr) ctxt->context->doc)
8114 return(NULL);
8115 switch (cur->type) {
8116 case XML_ELEMENT_NODE:
8117 case XML_TEXT_NODE:
8118 case XML_CDATA_SECTION_NODE:
8119 case XML_ENTITY_REF_NODE:
8120 case XML_ENTITY_NODE:
8121 case XML_PI_NODE:
8122 case XML_COMMENT_NODE:
8123 case XML_NOTATION_NODE:
8124 case XML_DTD_NODE:
8125 case XML_ELEMENT_DECL:
8126 case XML_ATTRIBUTE_DECL:
8127 case XML_ENTITY_DECL:
8128 case XML_XINCLUDE_START:
8129 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008130 if (cur->parent == NULL)
8131 return(NULL);
8132 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008133 ((cur->parent->name[0] == ' ') ||
8134 (xmlStrEqual(cur->parent->name,
8135 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008136 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008137 return(cur->parent);
8138 case XML_ATTRIBUTE_NODE: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008139 xmlAttrPtr att = (xmlAttrPtr) cur;
Owen Taylor3473f882001-02-23 17:55:21 +00008140
8141 return(att->parent);
8142 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008143 case XML_NAMESPACE_DECL: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008144 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008145
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008146 if ((ns->next != NULL) &&
8147 (ns->next->type != XML_NAMESPACE_DECL))
8148 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008149 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008150 return(NULL);
8151 }
Owen Taylor3473f882001-02-23 17:55:21 +00008152 case XML_DOCUMENT_NODE:
8153 case XML_DOCUMENT_TYPE_NODE:
8154 case XML_DOCUMENT_FRAG_NODE:
8155 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008156#ifdef LIBXML_DOCB_ENABLED
8157 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008158#endif
8159 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008160 }
8161 return(NULL);
8162}
8163
8164/**
8165 * xmlXPathNextAncestorOrSelf:
8166 * @ctxt: the XPath Parser context
8167 * @cur: the current node in the traversal
8168 *
8169 * Traversal function for the "ancestor-or-self" direction
8170 * he ancestor-or-self axis contains the context node and ancestors of
8171 * the context node in reverse document order; thus the context node is
8172 * the first node on the axis, and the context node's parent the second;
8173 * parent here is defined the same as with the parent axis.
8174 *
8175 * Returns the next element following that axis
8176 */
8177xmlNodePtr
8178xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008179 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008180 if (cur == NULL)
8181 return(ctxt->context->node);
8182 return(xmlXPathNextAncestor(ctxt, cur));
8183}
8184
8185/**
8186 * xmlXPathNextFollowingSibling:
8187 * @ctxt: the XPath Parser context
8188 * @cur: the current node in the traversal
8189 *
8190 * Traversal function for the "following-sibling" direction
8191 * The following-sibling axis contains the following siblings of the context
8192 * node in document order.
8193 *
8194 * Returns the next element following that axis
8195 */
8196xmlNodePtr
8197xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008198 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008199 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8200 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8201 return(NULL);
8202 if (cur == (xmlNodePtr) ctxt->context->doc)
8203 return(NULL);
8204 if (cur == NULL)
8205 return(ctxt->context->node->next);
8206 return(cur->next);
8207}
8208
8209/**
8210 * xmlXPathNextPrecedingSibling:
8211 * @ctxt: the XPath Parser context
8212 * @cur: the current node in the traversal
8213 *
8214 * Traversal function for the "preceding-sibling" direction
8215 * The preceding-sibling axis contains the preceding siblings of the context
8216 * node in reverse document order; the first preceding sibling is first on the
8217 * axis; the sibling preceding that node is the second on the axis and so on.
8218 *
8219 * Returns the next element following that axis
8220 */
8221xmlNodePtr
8222xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008223 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008224 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8225 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8226 return(NULL);
8227 if (cur == (xmlNodePtr) ctxt->context->doc)
8228 return(NULL);
8229 if (cur == NULL)
8230 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008231 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8232 cur = cur->prev;
8233 if (cur == NULL)
8234 return(ctxt->context->node->prev);
8235 }
Owen Taylor3473f882001-02-23 17:55:21 +00008236 return(cur->prev);
8237}
8238
8239/**
8240 * xmlXPathNextFollowing:
8241 * @ctxt: the XPath Parser context
8242 * @cur: the current node in the traversal
8243 *
8244 * Traversal function for the "following" direction
8245 * The following axis contains all nodes in the same document as the context
8246 * node that are after the context node in document order, excluding any
8247 * descendants and excluding attribute nodes and namespace nodes; the nodes
8248 * are ordered in document order
8249 *
8250 * Returns the next element following that axis
8251 */
8252xmlNodePtr
8253xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008254 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008255 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8256 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8257 return(cur->children);
8258
8259 if (cur == NULL) {
8260 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008261 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardea90b892010-10-22 15:50:50 +02008262 cur = cur->parent;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008263 } else if (cur->type == XML_NAMESPACE_DECL) {
8264 xmlNsPtr ns = (xmlNsPtr) cur;
8265
8266 if ((ns->next == NULL) ||
8267 (ns->next->type == XML_NAMESPACE_DECL))
8268 return (NULL);
8269 cur = (xmlNodePtr) ns->next;
8270 }
Daniel Veillard91d19752010-10-15 14:30:52 +02008271 }
Owen Taylor3473f882001-02-23 17:55:21 +00008272 if (cur == NULL) return(NULL) ; /* ERROR */
8273 if (cur->next != NULL) return(cur->next) ;
8274 do {
8275 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008276 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008277 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8278 if (cur->next != NULL) return(cur->next);
8279 } while (cur != NULL);
8280 return(cur);
8281}
8282
8283/*
8284 * xmlXPathIsAncestor:
8285 * @ancestor: the ancestor node
8286 * @node: the current node
8287 *
8288 * Check that @ancestor is a @node's ancestor
8289 *
8290 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8291 */
8292static int
8293xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8294 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008295 if (node->type == XML_NAMESPACE_DECL)
8296 return(0);
8297 if (ancestor->type == XML_NAMESPACE_DECL)
8298 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008299 /* nodes need to be in the same document */
8300 if (ancestor->doc != node->doc) return(0);
8301 /* avoid searching if ancestor or node is the root node */
8302 if (ancestor == (xmlNodePtr) node->doc) return(1);
8303 if (node == (xmlNodePtr) ancestor->doc) return(0);
8304 while (node->parent != NULL) {
8305 if (node->parent == ancestor)
8306 return(1);
8307 node = node->parent;
8308 }
8309 return(0);
8310}
8311
8312/**
8313 * xmlXPathNextPreceding:
8314 * @ctxt: the XPath Parser context
8315 * @cur: the current node in the traversal
8316 *
8317 * Traversal function for the "preceding" direction
8318 * the preceding axis contains all nodes in the same document as the context
8319 * node that are before the context node in document order, excluding any
8320 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8321 * ordered in reverse document order
8322 *
8323 * Returns the next element following that axis
8324 */
8325xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008326xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8327{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008328 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008329 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008330 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008331 if (cur->type == XML_ATTRIBUTE_NODE) {
8332 cur = cur->parent;
8333 } else if (cur->type == XML_NAMESPACE_DECL) {
8334 xmlNsPtr ns = (xmlNsPtr) cur;
8335
8336 if ((ns->next == NULL) ||
8337 (ns->next->type == XML_NAMESPACE_DECL))
8338 return (NULL);
8339 cur = (xmlNodePtr) ns->next;
8340 }
Daniel Veillardea90b892010-10-22 15:50:50 +02008341 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008342 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008343 return (NULL);
8344 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8345 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008346 do {
8347 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008348 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8349 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008350 }
8351
8352 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008353 if (cur == NULL)
8354 return (NULL);
8355 if (cur == ctxt->context->doc->children)
8356 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008357 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008358 return (cur);
8359}
8360
8361/**
8362 * xmlXPathNextPrecedingInternal:
8363 * @ctxt: the XPath Parser context
8364 * @cur: the current node in the traversal
8365 *
8366 * Traversal function for the "preceding" direction
8367 * the preceding axis contains all nodes in the same document as the context
8368 * node that are before the context node in document order, excluding any
8369 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8370 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008371 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008372 * state kept in the parser context: ctxt->ancestor.
8373 *
8374 * Returns the next element following that axis
8375 */
8376static xmlNodePtr
8377xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8378 xmlNodePtr cur)
8379{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008380 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008381 if (cur == NULL) {
8382 cur = ctxt->context->node;
8383 if (cur == NULL)
8384 return (NULL);
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008385 if (cur->type == XML_ATTRIBUTE_NODE) {
8386 cur = cur->parent;
8387 } else if (cur->type == XML_NAMESPACE_DECL) {
8388 xmlNsPtr ns = (xmlNsPtr) cur;
8389
8390 if ((ns->next == NULL) ||
8391 (ns->next->type == XML_NAMESPACE_DECL))
8392 return (NULL);
8393 cur = (xmlNodePtr) ns->next;
8394 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00008395 ctxt->ancestor = cur->parent;
8396 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008397 if (cur->type == XML_NAMESPACE_DECL)
8398 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008399 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8400 cur = cur->prev;
8401 while (cur->prev == NULL) {
8402 cur = cur->parent;
8403 if (cur == NULL)
8404 return (NULL);
8405 if (cur == ctxt->context->doc->children)
8406 return (NULL);
8407 if (cur != ctxt->ancestor)
8408 return (cur);
8409 ctxt->ancestor = cur->parent;
8410 }
8411 cur = cur->prev;
8412 while (cur->last != NULL)
8413 cur = cur->last;
8414 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008415}
8416
8417/**
8418 * xmlXPathNextNamespace:
8419 * @ctxt: the XPath Parser context
8420 * @cur: the current attribute in the traversal
8421 *
8422 * Traversal function for the "namespace" direction
8423 * the namespace axis contains the namespace nodes of the context node;
8424 * the order of nodes on this axis is implementation-defined; the axis will
8425 * be empty unless the context node is an element
8426 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008427 * We keep the XML namespace node at the end of the list.
8428 *
Owen Taylor3473f882001-02-23 17:55:21 +00008429 * Returns the next element following that axis
8430 */
8431xmlNodePtr
8432xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008433 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008434 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Nick Wellnhofer82b73032016-04-30 17:53:10 +02008435 if (cur == NULL) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008436 if (ctxt->context->tmpNsList != NULL)
8437 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008438 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008439 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008440 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008441 if (ctxt->context->tmpNsList != NULL) {
8442 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8443 ctxt->context->tmpNsNr++;
8444 }
8445 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008446 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008447 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008448 if (ctxt->context->tmpNsNr > 0) {
8449 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8450 } else {
8451 if (ctxt->context->tmpNsList != NULL)
8452 xmlFree(ctxt->context->tmpNsList);
8453 ctxt->context->tmpNsList = NULL;
8454 return(NULL);
8455 }
Owen Taylor3473f882001-02-23 17:55:21 +00008456}
8457
8458/**
8459 * xmlXPathNextAttribute:
8460 * @ctxt: the XPath Parser context
8461 * @cur: the current attribute in the traversal
8462 *
8463 * Traversal function for the "attribute" direction
8464 * TODO: support DTD inherited default attributes
8465 *
8466 * Returns the next element following that axis
8467 */
8468xmlNodePtr
8469xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008470 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008471 if (ctxt->context->node == NULL)
8472 return(NULL);
8473 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8474 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008475 if (cur == NULL) {
8476 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8477 return(NULL);
8478 return((xmlNodePtr)ctxt->context->node->properties);
8479 }
8480 return((xmlNodePtr)cur->next);
8481}
8482
8483/************************************************************************
8484 * *
8485 * NodeTest Functions *
8486 * *
8487 ************************************************************************/
8488
Owen Taylor3473f882001-02-23 17:55:21 +00008489#define IS_FUNCTION 200
8490
Owen Taylor3473f882001-02-23 17:55:21 +00008491
8492/************************************************************************
8493 * *
8494 * Implicit tree core function library *
8495 * *
8496 ************************************************************************/
8497
8498/**
8499 * xmlXPathRoot:
8500 * @ctxt: the XPath Parser context
8501 *
8502 * Initialize the context to the root of the document
8503 */
8504void
8505xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008506 if ((ctxt == NULL) || (ctxt->context == NULL))
8507 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008508 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008509 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8510 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008511}
8512
8513/************************************************************************
8514 * *
8515 * The explicit core function library *
8516 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8517 * *
8518 ************************************************************************/
8519
8520
8521/**
8522 * xmlXPathLastFunction:
8523 * @ctxt: the XPath Parser context
8524 * @nargs: the number of arguments
8525 *
8526 * Implement the last() XPath function
8527 * number last()
8528 * The last function returns the number of nodes in the context node list.
8529 */
8530void
8531xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8532 CHECK_ARITY(0);
8533 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008534 valuePush(ctxt,
8535 xmlXPathCacheNewFloat(ctxt->context,
8536 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008537#ifdef DEBUG_EXPR
8538 xmlGenericError(xmlGenericErrorContext,
8539 "last() : %d\n", ctxt->context->contextSize);
8540#endif
8541 } else {
8542 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8543 }
8544}
8545
8546/**
8547 * xmlXPathPositionFunction:
8548 * @ctxt: the XPath Parser context
8549 * @nargs: the number of arguments
8550 *
8551 * Implement the position() XPath function
8552 * number position()
8553 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008554 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008555 * will be equal to last().
8556 */
8557void
8558xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8559 CHECK_ARITY(0);
8560 if (ctxt->context->proximityPosition >= 0) {
8561 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008562 xmlXPathCacheNewFloat(ctxt->context,
8563 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008564#ifdef DEBUG_EXPR
8565 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8566 ctxt->context->proximityPosition);
8567#endif
8568 } else {
8569 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8570 }
8571}
8572
8573/**
8574 * xmlXPathCountFunction:
8575 * @ctxt: the XPath Parser context
8576 * @nargs: the number of arguments
8577 *
8578 * Implement the count() XPath function
8579 * number count(node-set)
8580 */
8581void
8582xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8583 xmlXPathObjectPtr cur;
8584
8585 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008586 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008587 ((ctxt->value->type != XPATH_NODESET) &&
8588 (ctxt->value->type != XPATH_XSLT_TREE)))
8589 XP_ERROR(XPATH_INVALID_TYPE);
8590 cur = valuePop(ctxt);
8591
Daniel Veillard911f49a2001-04-07 15:39:35 +00008592 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008593 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008594 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008595 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8596 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008597 } else {
8598 if ((cur->nodesetval->nodeNr != 1) ||
8599 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008600 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008601 } else {
8602 xmlNodePtr tmp;
8603 int i = 0;
8604
8605 tmp = cur->nodesetval->nodeTab[0];
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008606 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
Daniel Veillardfe703322001-08-14 12:18:09 +00008607 tmp = tmp->children;
8608 while (tmp != NULL) {
8609 tmp = tmp->next;
8610 i++;
8611 }
8612 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008613 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008614 }
8615 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008616 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008617}
8618
8619/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008620 * xmlXPathGetElementsByIds:
8621 * @doc: the document
8622 * @ids: a whitespace separated list of IDs
8623 *
8624 * Selects elements by their unique ID.
8625 *
8626 * Returns a node-set of selected elements.
8627 */
8628static xmlNodeSetPtr
8629xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8630 xmlNodeSetPtr ret;
8631 const xmlChar *cur = ids;
8632 xmlChar *ID;
8633 xmlAttrPtr attr;
8634 xmlNodePtr elem = NULL;
8635
Daniel Veillard7a985a12003-07-06 17:57:42 +00008636 if (ids == NULL) return(NULL);
8637
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008638 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008639 if (ret == NULL)
8640 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008641
William M. Brack76e95df2003-10-18 16:20:14 +00008642 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008643 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008644 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008645 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008646
8647 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008648 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008649 /*
8650 * We used to check the fact that the value passed
8651 * was an NCName, but this generated much troubles for
8652 * me and Aleksey Sanin, people blatantly violated that
8653 * constaint, like Visa3D spec.
8654 * if (xmlValidateNCName(ID, 1) == 0)
8655 */
8656 attr = xmlGetID(doc, ID);
8657 if (attr != NULL) {
8658 if (attr->type == XML_ATTRIBUTE_NODE)
8659 elem = attr->parent;
8660 else if (attr->type == XML_ELEMENT_NODE)
8661 elem = (xmlNodePtr) attr;
8662 else
8663 elem = NULL;
8664 if (elem != NULL)
8665 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008666 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008667 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008668 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008669
William M. Brack76e95df2003-10-18 16:20:14 +00008670 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008671 ids = cur;
8672 }
8673 return(ret);
8674}
8675
8676/**
Owen Taylor3473f882001-02-23 17:55:21 +00008677 * xmlXPathIdFunction:
8678 * @ctxt: the XPath Parser context
8679 * @nargs: the number of arguments
8680 *
8681 * Implement the id() XPath function
8682 * node-set id(object)
8683 * The id function selects elements by their unique ID
8684 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8685 * then the result is the union of the result of applying id to the
8686 * string value of each of the nodes in the argument node-set. When the
8687 * argument to id is of any other type, the argument is converted to a
8688 * string as if by a call to the string function; the string is split
8689 * into a whitespace-separated list of tokens (whitespace is any sequence
8690 * of characters matching the production S); the result is a node-set
8691 * containing the elements in the same document as the context node that
8692 * have a unique ID equal to any of the tokens in the list.
8693 */
8694void
8695xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008696 xmlChar *tokens;
8697 xmlNodeSetPtr ret;
8698 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008699
8700 CHECK_ARITY(1);
8701 obj = valuePop(ctxt);
8702 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008703 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008704 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008705 int i;
8706
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008707 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008708 /*
8709 * FIXME -- in an out-of-memory condition this will behave badly.
8710 * The solution is not clear -- we already popped an item from
8711 * ctxt, so the object is in a corrupt state.
8712 */
Owen Taylor3473f882001-02-23 17:55:21 +00008713
Daniel Veillard911f49a2001-04-07 15:39:35 +00008714 if (obj->nodesetval != NULL) {
8715 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008716 tokens =
8717 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8718 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8719 ret = xmlXPathNodeSetMerge(ret, ns);
8720 xmlXPathFreeNodeSet(ns);
8721 if (tokens != NULL)
8722 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008723 }
Owen Taylor3473f882001-02-23 17:55:21 +00008724 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008725 xmlXPathReleaseObject(ctxt->context, obj);
8726 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008727 return;
8728 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008729 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008730 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008731 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008732 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008733 return;
8734}
8735
8736/**
8737 * xmlXPathLocalNameFunction:
8738 * @ctxt: the XPath Parser context
8739 * @nargs: the number of arguments
8740 *
8741 * Implement the local-name() XPath function
8742 * string local-name(node-set?)
8743 * The local-name function returns a string containing the local part
8744 * of the name of the node in the argument node-set that is first in
8745 * document order. If the node-set is empty or the first node has no
8746 * name, an empty string is returned. If the argument is omitted it
8747 * defaults to the context node.
8748 */
8749void
8750xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8751 xmlXPathObjectPtr cur;
8752
Daniel Veillarda82b1822004-11-08 16:24:57 +00008753 if (ctxt == NULL) return;
8754
Owen Taylor3473f882001-02-23 17:55:21 +00008755 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008756 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8757 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008758 nargs = 1;
8759 }
8760
8761 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008762 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008763 ((ctxt->value->type != XPATH_NODESET) &&
8764 (ctxt->value->type != XPATH_XSLT_TREE)))
8765 XP_ERROR(XPATH_INVALID_TYPE);
8766 cur = valuePop(ctxt);
8767
Daniel Veillard911f49a2001-04-07 15:39:35 +00008768 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008769 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008770 } else {
8771 int i = 0; /* Should be first in document order !!!!! */
8772 switch (cur->nodesetval->nodeTab[i]->type) {
8773 case XML_ELEMENT_NODE:
8774 case XML_ATTRIBUTE_NODE:
8775 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008776 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008777 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008778 else
8779 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008780 xmlXPathCacheNewString(ctxt->context,
8781 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008782 break;
8783 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008784 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008785 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8786 break;
8787 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008788 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008789 }
8790 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008791 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008792}
8793
8794/**
8795 * xmlXPathNamespaceURIFunction:
8796 * @ctxt: the XPath Parser context
8797 * @nargs: the number of arguments
8798 *
8799 * Implement the namespace-uri() XPath function
8800 * string namespace-uri(node-set?)
8801 * The namespace-uri function returns a string containing the
8802 * namespace URI of the expanded name of the node in the argument
8803 * node-set that is first in document order. If the node-set is empty,
8804 * the first node has no name, or the expanded name has no namespace
8805 * URI, an empty string is returned. If the argument is omitted it
8806 * defaults to the context node.
8807 */
8808void
8809xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8810 xmlXPathObjectPtr cur;
8811
Daniel Veillarda82b1822004-11-08 16:24:57 +00008812 if (ctxt == NULL) return;
8813
Owen Taylor3473f882001-02-23 17:55:21 +00008814 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008815 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8816 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008817 nargs = 1;
8818 }
8819 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008820 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008821 ((ctxt->value->type != XPATH_NODESET) &&
8822 (ctxt->value->type != XPATH_XSLT_TREE)))
8823 XP_ERROR(XPATH_INVALID_TYPE);
8824 cur = valuePop(ctxt);
8825
Daniel Veillard911f49a2001-04-07 15:39:35 +00008826 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008827 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008828 } else {
8829 int i = 0; /* Should be first in document order !!!!! */
8830 switch (cur->nodesetval->nodeTab[i]->type) {
8831 case XML_ELEMENT_NODE:
8832 case XML_ATTRIBUTE_NODE:
8833 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008834 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008835 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008836 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008837 cur->nodesetval->nodeTab[i]->ns->href));
8838 break;
8839 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008840 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008841 }
8842 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008843 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008844}
8845
8846/**
8847 * xmlXPathNameFunction:
8848 * @ctxt: the XPath Parser context
8849 * @nargs: the number of arguments
8850 *
8851 * Implement the name() XPath function
8852 * string name(node-set?)
8853 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008854 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008855 * order. The QName must represent the name with respect to the namespace
8856 * declarations in effect on the node whose name is being represented.
8857 * Typically, this will be the form in which the name occurred in the XML
8858 * source. This need not be the case if there are namespace declarations
8859 * in effect on the node that associate multiple prefixes with the same
8860 * namespace. However, an implementation may include information about
8861 * the original prefix in its representation of nodes; in this case, an
8862 * implementation can ensure that the returned string is always the same
8863 * as the QName used in the XML source. If the argument it omitted it
8864 * defaults to the context node.
8865 * Libxml keep the original prefix so the "real qualified name" used is
8866 * returned.
8867 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008868static void
Daniel Veillard04383752001-07-08 14:27:15 +00008869xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8870{
Owen Taylor3473f882001-02-23 17:55:21 +00008871 xmlXPathObjectPtr cur;
8872
8873 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008874 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8875 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008876 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008877 }
8878
8879 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008880 if ((ctxt->value == NULL) ||
8881 ((ctxt->value->type != XPATH_NODESET) &&
8882 (ctxt->value->type != XPATH_XSLT_TREE)))
8883 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008884 cur = valuePop(ctxt);
8885
Daniel Veillard911f49a2001-04-07 15:39:35 +00008886 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008887 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008888 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008889 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008890
Daniel Veillard04383752001-07-08 14:27:15 +00008891 switch (cur->nodesetval->nodeTab[i]->type) {
8892 case XML_ELEMENT_NODE:
8893 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008894 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008895 valuePush(ctxt,
8896 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008897 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8898 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008899 valuePush(ctxt,
8900 xmlXPathCacheNewString(ctxt->context,
8901 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008902 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008903 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008904
Daniel Veillardc00cda82003-04-07 10:22:39 +00008905 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8906 cur->nodesetval->nodeTab[i]->ns->prefix,
8907 NULL, 0);
8908 if (fullname == cur->nodesetval->nodeTab[i]->name)
8909 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8910 if (fullname == NULL) {
8911 XP_ERROR(XPATH_MEMORY_ERROR);
8912 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008913 valuePush(ctxt, xmlXPathCacheWrapString(
8914 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008915 }
8916 break;
8917 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008918 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8919 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008920 xmlXPathLocalNameFunction(ctxt, 1);
8921 }
Owen Taylor3473f882001-02-23 17:55:21 +00008922 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008923 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008924}
8925
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008926
8927/**
Owen Taylor3473f882001-02-23 17:55:21 +00008928 * xmlXPathStringFunction:
8929 * @ctxt: the XPath Parser context
8930 * @nargs: the number of arguments
8931 *
8932 * Implement the string() XPath function
8933 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008934 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008935 * - A node-set is converted to a string by returning the value of
8936 * the node in the node-set that is first in document order.
8937 * If the node-set is empty, an empty string is returned.
8938 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008939 * + NaN is converted to the string NaN
8940 * + positive zero is converted to the string 0
8941 * + negative zero is converted to the string 0
8942 * + positive infinity is converted to the string Infinity
8943 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008944 * + if the number is an integer, the number is represented in
8945 * decimal form as a Number with no decimal point and no leading
8946 * zeros, preceded by a minus sign (-) if the number is negative
8947 * + otherwise, the number is represented in decimal form as a
8948 * Number including a decimal point with at least one digit
8949 * before the decimal point and at least one digit after the
8950 * decimal point, preceded by a minus sign (-) if the number
8951 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008952 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008953 * before the decimal point; beyond the one required digit
8954 * after the decimal point there must be as many, but only as
8955 * many, more digits as are needed to uniquely distinguish the
8956 * number from all other IEEE 754 numeric values.
8957 * - The boolean false value is converted to the string false.
8958 * The boolean true value is converted to the string true.
8959 *
8960 * If the argument is omitted, it defaults to a node-set with the
8961 * context node as its only member.
8962 */
8963void
8964xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8965 xmlXPathObjectPtr cur;
8966
Daniel Veillarda82b1822004-11-08 16:24:57 +00008967 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008968 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008969 valuePush(ctxt,
8970 xmlXPathCacheWrapString(ctxt->context,
8971 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008972 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008973 }
8974
8975 CHECK_ARITY(1);
8976 cur = valuePop(ctxt);
8977 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008978 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008979}
8980
8981/**
8982 * xmlXPathStringLengthFunction:
8983 * @ctxt: the XPath Parser context
8984 * @nargs: the number of arguments
8985 *
8986 * Implement the string-length() XPath function
8987 * number string-length(string?)
8988 * The string-length returns the number of characters in the string
8989 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8990 * the context node converted to a string, in other words the value
8991 * of the context node.
8992 */
8993void
8994xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8995 xmlXPathObjectPtr cur;
8996
8997 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008998 if ((ctxt == NULL) || (ctxt->context == NULL))
8999 return;
Owen Taylor3473f882001-02-23 17:55:21 +00009000 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009001 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009002 } else {
9003 xmlChar *content;
9004
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009005 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009006 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9007 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00009008 xmlFree(content);
9009 }
9010 return;
9011 }
9012 CHECK_ARITY(1);
9013 CAST_TO_STRING;
9014 CHECK_TYPE(XPATH_STRING);
9015 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009016 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00009017 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009018 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009019}
9020
9021/**
9022 * xmlXPathConcatFunction:
9023 * @ctxt: the XPath Parser context
9024 * @nargs: the number of arguments
9025 *
9026 * Implement the concat() XPath function
9027 * string concat(string, string, string*)
9028 * The concat function returns the concatenation of its arguments.
9029 */
9030void
9031xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9032 xmlXPathObjectPtr cur, newobj;
9033 xmlChar *tmp;
9034
Daniel Veillarda82b1822004-11-08 16:24:57 +00009035 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009036 if (nargs < 2) {
9037 CHECK_ARITY(2);
9038 }
9039
9040 CAST_TO_STRING;
9041 cur = valuePop(ctxt);
9042 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009043 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009044 return;
9045 }
9046 nargs--;
9047
9048 while (nargs > 0) {
9049 CAST_TO_STRING;
9050 newobj = valuePop(ctxt);
9051 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009052 xmlXPathReleaseObject(ctxt->context, newobj);
9053 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009054 XP_ERROR(XPATH_INVALID_TYPE);
9055 }
9056 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9057 newobj->stringval = cur->stringval;
9058 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009059 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00009060 nargs--;
9061 }
9062 valuePush(ctxt, cur);
9063}
9064
9065/**
9066 * xmlXPathContainsFunction:
9067 * @ctxt: the XPath Parser context
9068 * @nargs: the number of arguments
9069 *
9070 * Implement the contains() XPath function
9071 * boolean contains(string, string)
9072 * The contains function returns true if the first argument string
9073 * contains the second argument string, and otherwise returns false.
9074 */
9075void
9076xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9077 xmlXPathObjectPtr hay, needle;
9078
9079 CHECK_ARITY(2);
9080 CAST_TO_STRING;
9081 CHECK_TYPE(XPATH_STRING);
9082 needle = valuePop(ctxt);
9083 CAST_TO_STRING;
9084 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009085
Owen Taylor3473f882001-02-23 17:55:21 +00009086 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009087 xmlXPathReleaseObject(ctxt->context, hay);
9088 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009089 XP_ERROR(XPATH_INVALID_TYPE);
9090 }
9091 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009092 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009093 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009094 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9095 xmlXPathReleaseObject(ctxt->context, hay);
9096 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009097}
9098
9099/**
9100 * xmlXPathStartsWithFunction:
9101 * @ctxt: the XPath Parser context
9102 * @nargs: the number of arguments
9103 *
9104 * Implement the starts-with() XPath function
9105 * boolean starts-with(string, string)
9106 * The starts-with function returns true if the first argument string
9107 * starts with the second argument string, and otherwise returns false.
9108 */
9109void
9110xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9111 xmlXPathObjectPtr hay, needle;
9112 int n;
9113
9114 CHECK_ARITY(2);
9115 CAST_TO_STRING;
9116 CHECK_TYPE(XPATH_STRING);
9117 needle = valuePop(ctxt);
9118 CAST_TO_STRING;
9119 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009120
Owen Taylor3473f882001-02-23 17:55:21 +00009121 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009122 xmlXPathReleaseObject(ctxt->context, hay);
9123 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009124 XP_ERROR(XPATH_INVALID_TYPE);
9125 }
9126 n = xmlStrlen(needle->stringval);
9127 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009128 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009129 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009130 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9131 xmlXPathReleaseObject(ctxt->context, hay);
9132 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009133}
9134
9135/**
9136 * xmlXPathSubstringFunction:
9137 * @ctxt: the XPath Parser context
9138 * @nargs: the number of arguments
9139 *
9140 * Implement the substring() XPath function
9141 * string substring(string, number, number?)
9142 * The substring function returns the substring of the first argument
9143 * starting at the position specified in the second argument with
9144 * length specified in the third argument. For example,
9145 * substring("12345",2,3) returns "234". If the third argument is not
9146 * specified, it returns the substring starting at the position specified
9147 * in the second argument and continuing to the end of the string. For
9148 * example, substring("12345",2) returns "2345". More precisely, each
9149 * character in the string (see [3.6 Strings]) is considered to have a
9150 * numeric position: the position of the first character is 1, the position
9151 * of the second character is 2 and so on. The returned substring contains
9152 * those characters for which the position of the character is greater than
9153 * or equal to the second argument and, if the third argument is specified,
9154 * less than the sum of the second and third arguments; the comparisons
9155 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009156 * - substring("12345", 1.5, 2.6) returns "234"
9157 * - substring("12345", 0, 3) returns "12"
9158 * - substring("12345", 0 div 0, 3) returns ""
9159 * - substring("12345", 1, 0 div 0) returns ""
9160 * - substring("12345", -42, 1 div 0) returns "12345"
9161 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009162 */
9163void
9164xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9165 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009166 double le=0, in;
9167 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009168 xmlChar *ret;
9169
Owen Taylor3473f882001-02-23 17:55:21 +00009170 if (nargs < 2) {
9171 CHECK_ARITY(2);
9172 }
9173 if (nargs > 3) {
9174 CHECK_ARITY(3);
9175 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009176 /*
9177 * take care of possible last (position) argument
9178 */
Owen Taylor3473f882001-02-23 17:55:21 +00009179 if (nargs == 3) {
9180 CAST_TO_NUMBER;
9181 CHECK_TYPE(XPATH_NUMBER);
9182 len = valuePop(ctxt);
9183 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009184 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009185 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009186
Owen Taylor3473f882001-02-23 17:55:21 +00009187 CAST_TO_NUMBER;
9188 CHECK_TYPE(XPATH_NUMBER);
9189 start = valuePop(ctxt);
9190 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009191 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009192 CAST_TO_STRING;
9193 CHECK_TYPE(XPATH_STRING);
9194 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009195 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009196
Daniel Veillard97ac1312001-05-30 19:14:17 +00009197 /*
9198 * If last pos not present, calculate last position
9199 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009200 if (nargs != 3) {
9201 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009202 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009203 in = 1.0;
9204 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009205
Daniel Veillard45490ae2008-07-29 09:13:19 +00009206 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009207 * the index is NaN, the length is NaN, or both
9208 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009209 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009210 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009211 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009212 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009213 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009214 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009215 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009216 * First we go to integer form, rounding up
9217 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009218 */
9219 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009220 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009221
Daniel Veillard9e412302002-06-10 15:59:44 +00009222 if (xmlXPathIsInf(le) == 1) {
9223 l = m;
9224 if (i < 1)
9225 i = 1;
9226 }
9227 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9228 l = 0;
9229 else {
9230 l = (int) le;
9231 if (((double)l)+0.5 <= le) l++;
9232 }
9233
9234 /* Now we normalize inidices */
9235 i -= 1;
9236 l += i;
9237 if (i < 0)
9238 i = 0;
9239 if (l > m)
9240 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009241
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009242 /* number of chars to copy */
9243 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009244
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009245 ret = xmlUTF8Strsub(str->stringval, i, l);
9246 }
9247 else {
9248 ret = NULL;
9249 }
Owen Taylor3473f882001-02-23 17:55:21 +00009250 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009251 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009252 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009253 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009254 xmlFree(ret);
9255 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009256 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009257}
9258
9259/**
9260 * xmlXPathSubstringBeforeFunction:
9261 * @ctxt: the XPath Parser context
9262 * @nargs: the number of arguments
9263 *
9264 * Implement the substring-before() XPath function
9265 * string substring-before(string, string)
9266 * The substring-before function returns the substring of the first
9267 * argument string that precedes the first occurrence of the second
9268 * argument string in the first argument string, or the empty string
9269 * if the first argument string does not contain the second argument
9270 * string. For example, substring-before("1999/04/01","/") returns 1999.
9271 */
9272void
9273xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9274 xmlXPathObjectPtr str;
9275 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009276 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009277 const xmlChar *point;
9278 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009279
Owen Taylor3473f882001-02-23 17:55:21 +00009280 CHECK_ARITY(2);
9281 CAST_TO_STRING;
9282 find = valuePop(ctxt);
9283 CAST_TO_STRING;
9284 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009285
Daniel Veillardade10f22012-07-12 09:43:27 +08009286 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009287 if (target) {
9288 point = xmlStrstr(str->stringval, find->stringval);
9289 if (point) {
9290 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009291 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009292 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009293 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009294 xmlBufContent(target)));
9295 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009296 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009297 xmlXPathReleaseObject(ctxt->context, str);
9298 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009299}
9300
9301/**
9302 * xmlXPathSubstringAfterFunction:
9303 * @ctxt: the XPath Parser context
9304 * @nargs: the number of arguments
9305 *
9306 * Implement the substring-after() XPath function
9307 * string substring-after(string, string)
9308 * The substring-after function returns the substring of the first
9309 * argument string that follows the first occurrence of the second
9310 * argument string in the first argument string, or the empty stringi
9311 * if the first argument string does not contain the second argument
9312 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9313 * and substring-after("1999/04/01","19") returns 99/04/01.
9314 */
9315void
9316xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9317 xmlXPathObjectPtr str;
9318 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009319 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009320 const xmlChar *point;
9321 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009322
Owen Taylor3473f882001-02-23 17:55:21 +00009323 CHECK_ARITY(2);
9324 CAST_TO_STRING;
9325 find = valuePop(ctxt);
9326 CAST_TO_STRING;
9327 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009328
Daniel Veillardade10f22012-07-12 09:43:27 +08009329 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009330 if (target) {
9331 point = xmlStrstr(str->stringval, find->stringval);
9332 if (point) {
9333 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009334 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009335 xmlStrlen(str->stringval) - offset);
9336 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009337 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009338 xmlBufContent(target)));
9339 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009340 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009341 xmlXPathReleaseObject(ctxt->context, str);
9342 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009343}
9344
9345/**
9346 * xmlXPathNormalizeFunction:
9347 * @ctxt: the XPath Parser context
9348 * @nargs: the number of arguments
9349 *
9350 * Implement the normalize-space() XPath function
9351 * string normalize-space(string?)
9352 * The normalize-space function returns the argument string with white
9353 * space normalized by stripping leading and trailing whitespace
9354 * and replacing sequences of whitespace characters by a single
9355 * space. Whitespace characters are the same allowed by the S production
9356 * in XML. If the argument is omitted, it defaults to the context
9357 * node converted to a string, in other words the value of the context node.
9358 */
9359void
9360xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9361 xmlXPathObjectPtr obj = NULL;
9362 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009363 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009364 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009365
Daniel Veillarda82b1822004-11-08 16:24:57 +00009366 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009367 if (nargs == 0) {
9368 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009369 valuePush(ctxt,
9370 xmlXPathCacheWrapString(ctxt->context,
9371 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009372 nargs = 1;
9373 }
9374
9375 CHECK_ARITY(1);
9376 CAST_TO_STRING;
9377 CHECK_TYPE(XPATH_STRING);
9378 obj = valuePop(ctxt);
9379 source = obj->stringval;
9380
Daniel Veillardade10f22012-07-12 09:43:27 +08009381 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009382 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009383
Owen Taylor3473f882001-02-23 17:55:21 +00009384 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009385 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009386 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009387
Owen Taylor3473f882001-02-23 17:55:21 +00009388 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9389 blank = 0;
9390 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009391 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009392 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009393 } else {
9394 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009395 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009396 blank = 0;
9397 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009398 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009399 }
9400 source++;
9401 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009402 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009403 xmlBufContent(target)));
9404 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009405 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009406 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009407}
9408
9409/**
9410 * xmlXPathTranslateFunction:
9411 * @ctxt: the XPath Parser context
9412 * @nargs: the number of arguments
9413 *
9414 * Implement the translate() XPath function
9415 * string translate(string, string, string)
9416 * The translate function returns the first argument string with
9417 * occurrences of characters in the second argument string replaced
9418 * by the character at the corresponding position in the third argument
9419 * string. For example, translate("bar","abc","ABC") returns the string
9420 * BAr. If there is a character in the second argument string with no
9421 * character at a corresponding position in the third argument string
9422 * (because the second argument string is longer than the third argument
9423 * string), then occurrences of that character in the first argument
9424 * string are removed. For example, translate("--aaa--","abc-","ABC")
9425 * returns "AAA". If a character occurs more than once in second
9426 * argument string, then the first occurrence determines the replacement
9427 * character. If the third argument string is longer than the second
9428 * argument string, then excess characters are ignored.
9429 */
9430void
9431xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009432 xmlXPathObjectPtr str;
9433 xmlXPathObjectPtr from;
9434 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009435 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009436 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009437 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009438 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009439 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009440
Daniel Veillarde043ee12001-04-16 14:08:07 +00009441 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009442
Daniel Veillarde043ee12001-04-16 14:08:07 +00009443 CAST_TO_STRING;
9444 to = valuePop(ctxt);
9445 CAST_TO_STRING;
9446 from = valuePop(ctxt);
9447 CAST_TO_STRING;
9448 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009449
Daniel Veillardade10f22012-07-12 09:43:27 +08009450 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009451 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009452 max = xmlUTF8Strlen(to->stringval);
9453 for (cptr = str->stringval; (ch=*cptr); ) {
9454 offset = xmlUTF8Strloc(from->stringval, cptr);
9455 if (offset >= 0) {
9456 if (offset < max) {
9457 point = xmlUTF8Strpos(to->stringval, offset);
9458 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009459 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009460 }
9461 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009462 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009463
9464 /* Step to next character in input */
9465 cptr++;
9466 if ( ch & 0x80 ) {
9467 /* if not simple ascii, verify proper format */
9468 if ( (ch & 0xc0) != 0xc0 ) {
9469 xmlGenericError(xmlGenericErrorContext,
9470 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009471 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009472 break;
9473 }
9474 /* then skip over remaining bytes for this char */
9475 while ( (ch <<= 1) & 0x80 )
9476 if ( (*cptr++ & 0xc0) != 0x80 ) {
9477 xmlGenericError(xmlGenericErrorContext,
9478 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009479 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009480 break;
9481 }
9482 if (ch & 0x80) /* must have had error encountered */
9483 break;
9484 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009485 }
Owen Taylor3473f882001-02-23 17:55:21 +00009486 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009487 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009488 xmlBufContent(target)));
9489 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009490 xmlXPathReleaseObject(ctxt->context, str);
9491 xmlXPathReleaseObject(ctxt->context, from);
9492 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009493}
9494
9495/**
9496 * xmlXPathBooleanFunction:
9497 * @ctxt: the XPath Parser context
9498 * @nargs: the number of arguments
9499 *
9500 * Implement the boolean() XPath function
9501 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009502 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009503 * - a number is true if and only if it is neither positive or
9504 * negative zero nor NaN
9505 * - a node-set is true if and only if it is non-empty
9506 * - a string is true if and only if its length is non-zero
9507 */
9508void
9509xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9510 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009511
9512 CHECK_ARITY(1);
9513 cur = valuePop(ctxt);
9514 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009515 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009516 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009517}
9518
9519/**
9520 * xmlXPathNotFunction:
9521 * @ctxt: the XPath Parser context
9522 * @nargs: the number of arguments
9523 *
9524 * Implement the not() XPath function
9525 * boolean not(boolean)
9526 * The not function returns true if its argument is false,
9527 * and false otherwise.
9528 */
9529void
9530xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9531 CHECK_ARITY(1);
9532 CAST_TO_BOOLEAN;
9533 CHECK_TYPE(XPATH_BOOLEAN);
9534 ctxt->value->boolval = ! ctxt->value->boolval;
9535}
9536
9537/**
9538 * xmlXPathTrueFunction:
9539 * @ctxt: the XPath Parser context
9540 * @nargs: the number of arguments
9541 *
9542 * Implement the true() XPath function
9543 * boolean true()
9544 */
9545void
9546xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9547 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009548 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009549}
9550
9551/**
9552 * xmlXPathFalseFunction:
9553 * @ctxt: the XPath Parser context
9554 * @nargs: the number of arguments
9555 *
9556 * Implement the false() XPath function
9557 * boolean false()
9558 */
9559void
9560xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9561 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009562 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009563}
9564
9565/**
9566 * xmlXPathLangFunction:
9567 * @ctxt: the XPath Parser context
9568 * @nargs: the number of arguments
9569 *
9570 * Implement the lang() XPath function
9571 * boolean lang(string)
9572 * The lang function returns true or false depending on whether the
9573 * language of the context node as specified by xml:lang attributes
9574 * is the same as or is a sublanguage of the language specified by
9575 * the argument string. The language of the context node is determined
9576 * by the value of the xml:lang attribute on the context node, or, if
9577 * the context node has no xml:lang attribute, by the value of the
9578 * xml:lang attribute on the nearest ancestor of the context node that
9579 * has an xml:lang attribute. If there is no such attribute, then lang
9580 * returns false. If there is such an attribute, then lang returns
9581 * true if the attribute value is equal to the argument ignoring case,
9582 * or if there is some suffix starting with - such that the attribute
9583 * value is equal to the argument ignoring that suffix of the attribute
9584 * value and ignoring case.
9585 */
9586void
9587xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009588 xmlXPathObjectPtr val = NULL;
9589 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009590 const xmlChar *lang;
9591 int ret = 0;
9592 int i;
9593
9594 CHECK_ARITY(1);
9595 CAST_TO_STRING;
9596 CHECK_TYPE(XPATH_STRING);
9597 val = valuePop(ctxt);
9598 lang = val->stringval;
9599 theLang = xmlNodeGetLang(ctxt->context->node);
9600 if ((theLang != NULL) && (lang != NULL)) {
9601 for (i = 0;lang[i] != 0;i++)
9602 if (toupper(lang[i]) != toupper(theLang[i]))
9603 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009604 if ((theLang[i] == 0) || (theLang[i] == '-'))
9605 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009606 }
9607not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009608 if (theLang != NULL)
9609 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009610
9611 xmlXPathReleaseObject(ctxt->context, val);
9612 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009613}
9614
9615/**
9616 * xmlXPathNumberFunction:
9617 * @ctxt: the XPath Parser context
9618 * @nargs: the number of arguments
9619 *
9620 * Implement the number() XPath function
9621 * number number(object?)
9622 */
9623void
9624xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9625 xmlXPathObjectPtr cur;
9626 double res;
9627
Daniel Veillarda82b1822004-11-08 16:24:57 +00009628 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009629 if (nargs == 0) {
9630 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009631 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009632 } else {
9633 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9634
9635 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009636 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009637 xmlFree(content);
9638 }
9639 return;
9640 }
9641
9642 CHECK_ARITY(1);
9643 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009644 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009645}
9646
9647/**
9648 * xmlXPathSumFunction:
9649 * @ctxt: the XPath Parser context
9650 * @nargs: the number of arguments
9651 *
9652 * Implement the sum() XPath function
9653 * number sum(node-set)
9654 * The sum function returns the sum of the values of the nodes in
9655 * the argument node-set.
9656 */
9657void
9658xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9659 xmlXPathObjectPtr cur;
9660 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009661 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009662
9663 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009664 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009665 ((ctxt->value->type != XPATH_NODESET) &&
9666 (ctxt->value->type != XPATH_XSLT_TREE)))
9667 XP_ERROR(XPATH_INVALID_TYPE);
9668 cur = valuePop(ctxt);
9669
William M. Brack08171912003-12-29 02:52:11 +00009670 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009671 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9672 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009673 }
9674 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009675 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9676 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009677}
9678
9679/**
9680 * xmlXPathFloorFunction:
9681 * @ctxt: the XPath Parser context
9682 * @nargs: the number of arguments
9683 *
9684 * Implement the floor() XPath function
9685 * number floor(number)
9686 * The floor function returns the largest (closest to positive infinity)
9687 * number that is not greater than the argument and that is an integer.
9688 */
9689void
9690xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9691 CHECK_ARITY(1);
9692 CAST_TO_NUMBER;
9693 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009694
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009695 ctxt->value->floatval = floor(ctxt->value->floatval);
Owen Taylor3473f882001-02-23 17:55:21 +00009696}
9697
9698/**
9699 * xmlXPathCeilingFunction:
9700 * @ctxt: the XPath Parser context
9701 * @nargs: the number of arguments
9702 *
9703 * Implement the ceiling() XPath function
9704 * number ceiling(number)
9705 * The ceiling function returns the smallest (closest to negative infinity)
9706 * number that is not less than the argument and that is an integer.
9707 */
9708void
9709xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Owen Taylor3473f882001-02-23 17:55:21 +00009710 CHECK_ARITY(1);
9711 CAST_TO_NUMBER;
9712 CHECK_TYPE(XPATH_NUMBER);
9713
Owen Taylor3473f882001-02-23 17:55:21 +00009714 ctxt->value->floatval = ceil(ctxt->value->floatval);
Owen Taylor3473f882001-02-23 17:55:21 +00009715}
9716
9717/**
9718 * xmlXPathRoundFunction:
9719 * @ctxt: the XPath Parser context
9720 * @nargs: the number of arguments
9721 *
9722 * Implement the round() XPath function
9723 * number round(number)
9724 * The round function returns the number that is closest to the
9725 * argument and that is an integer. If there are two such numbers,
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009726 * then the one that is closest to positive infinity is returned.
Owen Taylor3473f882001-02-23 17:55:21 +00009727 */
9728void
9729xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9730 double f;
9731
9732 CHECK_ARITY(1);
9733 CAST_TO_NUMBER;
9734 CHECK_TYPE(XPATH_NUMBER);
9735
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009736 f = ctxt->value->floatval;
9737
9738 /* Test for zero to keep negative zero unchanged. */
9739 if ((xmlXPathIsNaN(f)) || (f == 0.0))
Owen Taylor3473f882001-02-23 17:55:21 +00009740 return;
9741
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009742 if ((f >= -0.5) && (f < 0.0)) {
9743 /* Negative zero. */
9744 ctxt->value->floatval = xmlXPathNZERO;
9745 }
9746 else {
9747 double rounded = floor(f);
9748 if (f - rounded >= 0.5)
9749 rounded += 1.0;
9750 ctxt->value->floatval = rounded;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009751 }
Owen Taylor3473f882001-02-23 17:55:21 +00009752}
9753
9754/************************************************************************
9755 * *
9756 * The Parser *
9757 * *
9758 ************************************************************************/
9759
9760/*
William M. Brack08171912003-12-29 02:52:11 +00009761 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009762 * implementation.
9763 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009764static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009765static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009766static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009767static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009768static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9769 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009770
9771/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009772 * xmlXPathCurrentChar:
9773 * @ctxt: the XPath parser context
9774 * @cur: pointer to the beginning of the char
9775 * @len: pointer to the length of the char read
9776 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009777 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009778 * bytes in the input buffer.
9779 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009780 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009781 */
9782
9783static int
9784xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9785 unsigned char c;
9786 unsigned int val;
9787 const xmlChar *cur;
9788
9789 if (ctxt == NULL)
9790 return(0);
9791 cur = ctxt->cur;
9792
9793 /*
9794 * We are supposed to handle UTF8, check it's valid
9795 * From rfc2044: encoding of the Unicode values on UTF-8:
9796 *
9797 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9798 * 0000 0000-0000 007F 0xxxxxxx
9799 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009800 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009801 *
9802 * Check for the 0x110000 limit too
9803 */
9804 c = *cur;
9805 if (c & 0x80) {
9806 if ((cur[1] & 0xc0) != 0x80)
9807 goto encoding_error;
9808 if ((c & 0xe0) == 0xe0) {
9809
9810 if ((cur[2] & 0xc0) != 0x80)
9811 goto encoding_error;
9812 if ((c & 0xf0) == 0xf0) {
9813 if (((c & 0xf8) != 0xf0) ||
9814 ((cur[3] & 0xc0) != 0x80))
9815 goto encoding_error;
9816 /* 4-byte code */
9817 *len = 4;
9818 val = (cur[0] & 0x7) << 18;
9819 val |= (cur[1] & 0x3f) << 12;
9820 val |= (cur[2] & 0x3f) << 6;
9821 val |= cur[3] & 0x3f;
9822 } else {
9823 /* 3-byte code */
9824 *len = 3;
9825 val = (cur[0] & 0xf) << 12;
9826 val |= (cur[1] & 0x3f) << 6;
9827 val |= cur[2] & 0x3f;
9828 }
9829 } else {
9830 /* 2-byte code */
9831 *len = 2;
9832 val = (cur[0] & 0x1f) << 6;
9833 val |= cur[1] & 0x3f;
9834 }
9835 if (!IS_CHAR(val)) {
9836 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009837 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009838 return(val);
9839 } else {
9840 /* 1-byte code */
9841 *len = 1;
9842 return((int) *cur);
9843 }
9844encoding_error:
9845 /*
William M. Brack08171912003-12-29 02:52:11 +00009846 * If we detect an UTF8 error that probably means that the
9847 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009848 * declaration header. Report the error and switch the encoding
9849 * to ISO-Latin-1 (if you don't like this policy, just declare the
9850 * encoding !)
9851 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009852 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009853 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009854}
9855
9856/**
Owen Taylor3473f882001-02-23 17:55:21 +00009857 * xmlXPathParseNCName:
9858 * @ctxt: the XPath Parser context
9859 *
9860 * parse an XML namespace non qualified name.
9861 *
9862 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9863 *
9864 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9865 * CombiningChar | Extender
9866 *
9867 * Returns the namespace name or NULL
9868 */
9869
9870xmlChar *
9871xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009872 const xmlChar *in;
9873 xmlChar *ret;
9874 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009875
Daniel Veillarda82b1822004-11-08 16:24:57 +00009876 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009877 /*
9878 * Accelerator for simple ASCII names
9879 */
9880 in = ctxt->cur;
9881 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9882 ((*in >= 0x41) && (*in <= 0x5A)) ||
9883 (*in == '_')) {
9884 in++;
9885 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9886 ((*in >= 0x41) && (*in <= 0x5A)) ||
9887 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009888 (*in == '_') || (*in == '.') ||
9889 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009890 in++;
9891 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9892 (*in == '[') || (*in == ']') || (*in == ':') ||
9893 (*in == '@') || (*in == '*')) {
9894 count = in - ctxt->cur;
9895 if (count == 0)
9896 return(NULL);
9897 ret = xmlStrndup(ctxt->cur, count);
9898 ctxt->cur = in;
9899 return(ret);
9900 }
9901 }
9902 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009903}
9904
Daniel Veillard2156a562001-04-28 12:24:34 +00009905
Owen Taylor3473f882001-02-23 17:55:21 +00009906/**
9907 * xmlXPathParseQName:
9908 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009909 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009910 *
9911 * parse an XML qualified name
9912 *
9913 * [NS 5] QName ::= (Prefix ':')? LocalPart
9914 *
9915 * [NS 6] Prefix ::= NCName
9916 *
9917 * [NS 7] LocalPart ::= NCName
9918 *
9919 * Returns the function returns the local part, and prefix is updated
9920 * to get the Prefix if any.
9921 */
9922
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009923static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009924xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9925 xmlChar *ret = NULL;
9926
9927 *prefix = NULL;
9928 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009929 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009930 *prefix = ret;
9931 NEXT;
9932 ret = xmlXPathParseNCName(ctxt);
9933 }
9934 return(ret);
9935}
9936
9937/**
9938 * xmlXPathParseName:
9939 * @ctxt: the XPath Parser context
9940 *
9941 * parse an XML name
9942 *
9943 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9944 * CombiningChar | Extender
9945 *
9946 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9947 *
9948 * Returns the namespace name or NULL
9949 */
9950
9951xmlChar *
9952xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009953 const xmlChar *in;
9954 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009955 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009956
Daniel Veillarda82b1822004-11-08 16:24:57 +00009957 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009958 /*
9959 * Accelerator for simple ASCII names
9960 */
9961 in = ctxt->cur;
9962 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9963 ((*in >= 0x41) && (*in <= 0x5A)) ||
9964 (*in == '_') || (*in == ':')) {
9965 in++;
9966 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9967 ((*in >= 0x41) && (*in <= 0x5A)) ||
9968 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009969 (*in == '_') || (*in == '-') ||
9970 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009971 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009972 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009973 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009974 if (count > XML_MAX_NAME_LENGTH) {
9975 ctxt->cur = in;
9976 XP_ERRORNULL(XPATH_EXPR_ERROR);
9977 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009978 ret = xmlStrndup(ctxt->cur, count);
9979 ctxt->cur = in;
9980 return(ret);
9981 }
9982 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009983 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009984}
9985
Daniel Veillard61d80a22001-04-27 17:13:01 +00009986static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009987xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009988 xmlChar buf[XML_MAX_NAMELEN + 5];
9989 int len = 0, l;
9990 int c;
9991
9992 /*
9993 * Handler for more complex cases
9994 */
9995 c = CUR_CHAR(l);
9996 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009997 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9998 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009999 (!IS_LETTER(c) && (c != '_') &&
Nick Wellnhofere2893902016-04-21 19:19:23 +020010000 ((!qualified) || (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +000010001 return(NULL);
10002 }
10003
10004 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10005 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10006 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010007 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +000010008 (IS_COMBINING(c)) ||
10009 (IS_EXTENDER(c)))) {
10010 COPY_BUF(l,buf,len,c);
10011 NEXTL(l);
10012 c = CUR_CHAR(l);
10013 if (len >= XML_MAX_NAMELEN) {
10014 /*
10015 * Okay someone managed to make a huge name, so he's ready to pay
10016 * for the processing speed.
10017 */
10018 xmlChar *buffer;
10019 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010020
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010021 if (len > XML_MAX_NAME_LENGTH) {
10022 XP_ERRORNULL(XPATH_EXPR_ERROR);
10023 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +000010024 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010025 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010026 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010027 }
10028 memcpy(buffer, buf, len);
10029 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10030 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010031 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +000010032 (IS_COMBINING(c)) ||
10033 (IS_EXTENDER(c))) {
10034 if (len + 10 > max) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010035 if (max > XML_MAX_NAME_LENGTH) {
10036 XP_ERRORNULL(XPATH_EXPR_ERROR);
10037 }
Daniel Veillard61d80a22001-04-27 17:13:01 +000010038 max *= 2;
10039 buffer = (xmlChar *) xmlRealloc(buffer,
10040 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010041 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010042 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010043 }
10044 }
10045 COPY_BUF(l,buffer,len,c);
10046 NEXTL(l);
10047 c = CUR_CHAR(l);
10048 }
10049 buffer[len] = 0;
10050 return(buffer);
10051 }
10052 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010053 if (len == 0)
10054 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010055 return(xmlStrndup(buf, len));
10056}
Daniel Veillard3cd72402002-05-13 10:33:30 +000010057
10058#define MAX_FRAC 20
10059
Owen Taylor3473f882001-02-23 17:55:21 +000010060/**
10061 * xmlXPathStringEvalNumber:
10062 * @str: A string to scan
10063 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000010064 * [30a] Float ::= Number ('e' Digits?)?
10065 *
Owen Taylor3473f882001-02-23 17:55:21 +000010066 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010067 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010068 * [31] Digits ::= [0-9]+
10069 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010070 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +000010071 * In complement of the Number expression, this function also handles
10072 * negative values : '-' Number.
10073 *
10074 * Returns the double value.
10075 */
10076double
10077xmlXPathStringEvalNumber(const xmlChar *str) {
10078 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +000010079 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010080 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010081 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010082 int exponent = 0;
10083 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010084#ifdef __GNUC__
10085 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010086 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010087#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010088 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +000010089 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010090 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10091 return(xmlXPathNAN);
10092 }
10093 if (*cur == '-') {
10094 isneg = 1;
10095 cur++;
10096 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010097
10098#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010099 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010100 * tmp/temp is a workaround against a gcc compiler bug
10101 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010102 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010103 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010104 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010105 ret = ret * 10;
10106 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010107 ok = 1;
10108 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010109 temp = (double) tmp;
10110 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010111 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010112#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010113 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010114 while ((*cur >= '0') && (*cur <= '9')) {
10115 ret = ret * 10 + (*cur - '0');
10116 ok = 1;
10117 cur++;
10118 }
10119#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010120
Owen Taylor3473f882001-02-23 17:55:21 +000010121 if (*cur == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010122 int v, frac = 0, max;
Daniel Veillard3cd72402002-05-13 10:33:30 +000010123 double fraction = 0;
10124
Owen Taylor3473f882001-02-23 17:55:21 +000010125 cur++;
10126 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10127 return(xmlXPathNAN);
10128 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010129 while (*cur == '0') {
10130 frac = frac + 1;
10131 cur++;
10132 }
10133 max = frac + MAX_FRAC;
10134 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010135 v = (*cur - '0');
10136 fraction = fraction * 10 + v;
10137 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010138 cur++;
10139 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010140 fraction /= pow(10.0, frac);
Daniel Veillard3cd72402002-05-13 10:33:30 +000010141 ret = ret + fraction;
10142 while ((*cur >= '0') && (*cur <= '9'))
10143 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010144 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010145 if ((*cur == 'e') || (*cur == 'E')) {
10146 cur++;
10147 if (*cur == '-') {
10148 is_exponent_negative = 1;
10149 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010150 } else if (*cur == '+') {
10151 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010152 }
10153 while ((*cur >= '0') && (*cur <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010154 if (exponent < 1000000)
10155 exponent = exponent * 10 + (*cur - '0');
Bjorn Reese70a9da52001-04-21 16:57:29 +000010156 cur++;
10157 }
10158 }
William M. Brack76e95df2003-10-18 16:20:14 +000010159 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010160 if (*cur != 0) return(xmlXPathNAN);
10161 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010162 if (is_exponent_negative) exponent = -exponent;
10163 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010164 return(ret);
10165}
10166
10167/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010168 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010169 * @ctxt: the XPath Parser context
10170 *
10171 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010172 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010173 * [31] Digits ::= [0-9]+
10174 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010175 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010176 *
10177 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010178static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010179xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10180{
Owen Taylor3473f882001-02-23 17:55:21 +000010181 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010182 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010183 int exponent = 0;
10184 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010185#ifdef __GNUC__
10186 unsigned long tmp = 0;
10187 double temp;
10188#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010189
10190 CHECK_ERROR;
10191 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10192 XP_ERROR(XPATH_NUMBER_ERROR);
10193 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010194#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010195 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010196 * tmp/temp is a workaround against a gcc compiler bug
10197 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010198 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010199 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010200 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010201 ret = ret * 10;
10202 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010203 ok = 1;
10204 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010205 temp = (double) tmp;
10206 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010207 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010208#else
10209 ret = 0;
10210 while ((CUR >= '0') && (CUR <= '9')) {
10211 ret = ret * 10 + (CUR - '0');
10212 ok = 1;
10213 NEXT;
10214 }
10215#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010216 if (CUR == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010217 int v, frac = 0, max;
Phil Shaferee32ad32010-11-03 20:53:55 +010010218 double fraction = 0;
10219
Owen Taylor3473f882001-02-23 17:55:21 +000010220 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010221 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10222 XP_ERROR(XPATH_NUMBER_ERROR);
10223 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010224 while (CUR == '0') {
10225 frac = frac + 1;
10226 NEXT;
10227 }
10228 max = frac + MAX_FRAC;
10229 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
Phil Shaferee32ad32010-11-03 20:53:55 +010010230 v = (CUR - '0');
10231 fraction = fraction * 10 + v;
10232 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010233 NEXT;
10234 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010235 fraction /= pow(10.0, frac);
Phil Shaferee32ad32010-11-03 20:53:55 +010010236 ret = ret + fraction;
10237 while ((CUR >= '0') && (CUR <= '9'))
10238 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010239 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010240 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010241 NEXT;
10242 if (CUR == '-') {
10243 is_exponent_negative = 1;
10244 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010245 } else if (CUR == '+') {
10246 NEXT;
10247 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010248 while ((CUR >= '0') && (CUR <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010249 if (exponent < 1000000)
10250 exponent = exponent * 10 + (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010251 NEXT;
10252 }
10253 if (is_exponent_negative)
10254 exponent = -exponent;
10255 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010256 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010257 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010258 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010259}
10260
10261/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010262 * xmlXPathParseLiteral:
10263 * @ctxt: the XPath Parser context
10264 *
10265 * Parse a Literal
10266 *
10267 * [29] Literal ::= '"' [^"]* '"'
10268 * | "'" [^']* "'"
10269 *
10270 * Returns the value found or NULL in case of error
10271 */
10272static xmlChar *
10273xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10274 const xmlChar *q;
10275 xmlChar *ret = NULL;
10276
10277 if (CUR == '"') {
10278 NEXT;
10279 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010280 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010281 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010282 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010283 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010284 } else {
10285 ret = xmlStrndup(q, CUR_PTR - q);
10286 NEXT;
10287 }
10288 } else if (CUR == '\'') {
10289 NEXT;
10290 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010291 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010292 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010293 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010294 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010295 } else {
10296 ret = xmlStrndup(q, CUR_PTR - q);
10297 NEXT;
10298 }
10299 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010300 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010301 }
10302 return(ret);
10303}
10304
10305/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010306 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010307 * @ctxt: the XPath Parser context
10308 *
10309 * Parse a Literal and push it on the stack.
10310 *
10311 * [29] Literal ::= '"' [^"]* '"'
10312 * | "'" [^']* "'"
10313 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010314 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010315 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010316static void
10317xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010318 const xmlChar *q;
10319 xmlChar *ret = NULL;
10320
10321 if (CUR == '"') {
10322 NEXT;
10323 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010324 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010325 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010326 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010327 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10328 } else {
10329 ret = xmlStrndup(q, CUR_PTR - q);
10330 NEXT;
10331 }
10332 } else if (CUR == '\'') {
10333 NEXT;
10334 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010335 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010336 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010337 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010338 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10339 } else {
10340 ret = xmlStrndup(q, CUR_PTR - q);
10341 NEXT;
10342 }
10343 } else {
10344 XP_ERROR(XPATH_START_LITERAL_ERROR);
10345 }
10346 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010347 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010348 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010349 xmlFree(ret);
10350}
10351
10352/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010353 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010354 * @ctxt: the XPath Parser context
10355 *
10356 * Parse a VariableReference, evaluate it and push it on the stack.
10357 *
10358 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010359 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010360 * of any of the types that are possible for the value of an expression,
10361 * and may also be of additional types not specified here.
10362 *
10363 * Early evaluation is possible since:
10364 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010365 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010366 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010367 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010368 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010369static void
10370xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010371 xmlChar *name;
10372 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010373
10374 SKIP_BLANKS;
10375 if (CUR != '$') {
10376 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10377 }
10378 NEXT;
10379 name = xmlXPathParseQName(ctxt, &prefix);
10380 if (name == NULL) {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010381 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010382 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10383 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010384 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010385 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10386 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010387 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010388 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
Daniel Veillard47881282012-09-07 14:24:50 +080010389 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
Daniel Veillardb3d14912005-09-04 20:47:39 +000010390 }
Owen Taylor3473f882001-02-23 17:55:21 +000010391}
10392
10393/**
10394 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010395 * @name: a name string
10396 *
10397 * Is the name given a NodeType one.
10398 *
10399 * [38] NodeType ::= 'comment'
10400 * | 'text'
10401 * | 'processing-instruction'
10402 * | 'node'
10403 *
10404 * Returns 1 if true 0 otherwise
10405 */
10406int
10407xmlXPathIsNodeType(const xmlChar *name) {
10408 if (name == NULL)
10409 return(0);
10410
Daniel Veillard1971ee22002-01-31 20:29:19 +000010411 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010412 return(1);
10413 if (xmlStrEqual(name, BAD_CAST "text"))
10414 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010415 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010416 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010417 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010418 return(1);
10419 return(0);
10420}
10421
10422/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010423 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010424 * @ctxt: the XPath Parser context
10425 *
10426 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010427 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010428 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010429 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010430 * pushed on the stack
10431 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010432static void
10433xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010434 xmlChar *name;
10435 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010436 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010437 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010438
10439 name = xmlXPathParseQName(ctxt, &prefix);
10440 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010441 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010442 XP_ERROR(XPATH_EXPR_ERROR);
10443 }
10444 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010445#ifdef DEBUG_EXPR
10446 if (prefix == NULL)
10447 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10448 name);
10449 else
10450 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10451 prefix, name);
10452#endif
10453
Owen Taylor3473f882001-02-23 17:55:21 +000010454 if (CUR != '(') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010455 xmlFree(name);
10456 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010457 XP_ERROR(XPATH_EXPR_ERROR);
10458 }
10459 NEXT;
10460 SKIP_BLANKS;
10461
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010462 /*
10463 * Optimization for count(): we don't need the node-set to be sorted.
10464 */
10465 if ((prefix == NULL) && (name[0] == 'c') &&
10466 xmlStrEqual(name, BAD_CAST "count"))
10467 {
10468 sort = 0;
10469 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010470 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010471 if (CUR != ')') {
10472 while (CUR != 0) {
10473 int op1 = ctxt->comp->last;
10474 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010475 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010476 if (ctxt->error != XPATH_EXPRESSION_OK) {
10477 xmlFree(name);
10478 xmlFree(prefix);
10479 return;
10480 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010481 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10482 nbargs++;
10483 if (CUR == ')') break;
10484 if (CUR != ',') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010485 xmlFree(name);
10486 xmlFree(prefix);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010487 XP_ERROR(XPATH_EXPR_ERROR);
10488 }
10489 NEXT;
10490 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010491 }
Owen Taylor3473f882001-02-23 17:55:21 +000010492 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010493 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10494 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010495 NEXT;
10496 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010497}
10498
10499/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010500 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010501 * @ctxt: the XPath Parser context
10502 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010503 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010504 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010505 * | Literal
10506 * | Number
10507 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010508 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010509 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010510 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010511static void
10512xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010513 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010514 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010515 else if (CUR == '(') {
10516 NEXT;
10517 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010518 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010519 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010520 if (CUR != ')') {
10521 XP_ERROR(XPATH_EXPR_ERROR);
10522 }
10523 NEXT;
10524 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010525 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010526 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010527 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010528 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010529 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010530 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010531 }
10532 SKIP_BLANKS;
10533}
10534
10535/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010536 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010537 * @ctxt: the XPath Parser context
10538 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010539 * [20] FilterExpr ::= PrimaryExpr
10540 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010541 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010542 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010543 * Square brackets are used to filter expressions in the same way that
10544 * they are used in location paths. It is an error if the expression to
10545 * be filtered does not evaluate to a node-set. The context node list
10546 * used for evaluating the expression in square brackets is the node-set
10547 * to be filtered listed in document order.
10548 */
10549
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010550static void
10551xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10552 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010553 CHECK_ERROR;
10554 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010555
Owen Taylor3473f882001-02-23 17:55:21 +000010556 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010557 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010558 SKIP_BLANKS;
10559 }
10560
Daniel Veillard45490ae2008-07-29 09:13:19 +000010561
Owen Taylor3473f882001-02-23 17:55:21 +000010562}
10563
10564/**
10565 * xmlXPathScanName:
10566 * @ctxt: the XPath Parser context
10567 *
10568 * Trickery: parse an XML name but without consuming the input flow
10569 * Needed to avoid insanity in the parser state.
10570 *
10571 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10572 * CombiningChar | Extender
10573 *
10574 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10575 *
10576 * [6] Names ::= Name (S Name)*
10577 *
10578 * Returns the Name parsed or NULL
10579 */
10580
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010581static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010582xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010583 int len = 0, l;
10584 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010585 const xmlChar *cur;
10586 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010587
Daniel Veillard03226812004-11-01 14:55:21 +000010588 cur = ctxt->cur;
10589
10590 c = CUR_CHAR(l);
10591 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10592 (!IS_LETTER(c) && (c != '_') &&
10593 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010594 return(NULL);
10595 }
10596
Daniel Veillard03226812004-11-01 14:55:21 +000010597 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10598 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10599 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010600 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010601 (IS_COMBINING(c)) ||
10602 (IS_EXTENDER(c)))) {
10603 len += l;
10604 NEXTL(l);
10605 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010606 }
Daniel Veillard03226812004-11-01 14:55:21 +000010607 ret = xmlStrndup(cur, ctxt->cur - cur);
10608 ctxt->cur = cur;
10609 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010610}
10611
10612/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010613 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010614 * @ctxt: the XPath Parser context
10615 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010616 * [19] PathExpr ::= LocationPath
10617 * | FilterExpr
10618 * | FilterExpr '/' RelativeLocationPath
10619 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010620 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010621 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010622 * The / operator and // operators combine an arbitrary expression
10623 * and a relative location path. It is an error if the expression
10624 * does not evaluate to a node-set.
10625 * The / operator does composition in the same way as when / is
10626 * used in a location path. As in location paths, // is short for
10627 * /descendant-or-self::node()/.
10628 */
10629
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010630static void
10631xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010632 int lc = 1; /* Should we branch to LocationPath ? */
10633 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10634
10635 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010636 if ((CUR == '$') || (CUR == '(') ||
10637 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010638 (CUR == '\'') || (CUR == '"') ||
10639 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010640 lc = 0;
10641 } else if (CUR == '*') {
10642 /* relative or absolute location path */
10643 lc = 1;
10644 } else if (CUR == '/') {
10645 /* relative or absolute location path */
10646 lc = 1;
10647 } else if (CUR == '@') {
10648 /* relative abbreviated attribute location path */
10649 lc = 1;
10650 } else if (CUR == '.') {
10651 /* relative abbreviated attribute location path */
10652 lc = 1;
10653 } else {
10654 /*
10655 * Problem is finding if we have a name here whether it's:
10656 * - a nodetype
10657 * - a function call in which case it's followed by '('
10658 * - an axis in which case it's followed by ':'
10659 * - a element name
10660 * We do an a priori analysis here rather than having to
10661 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010662 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010663 * read/write/debug.
10664 */
10665 SKIP_BLANKS;
10666 name = xmlXPathScanName(ctxt);
10667 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10668#ifdef DEBUG_STEP
10669 xmlGenericError(xmlGenericErrorContext,
10670 "PathExpr: Axis\n");
10671#endif
10672 lc = 1;
10673 xmlFree(name);
10674 } else if (name != NULL) {
10675 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010676
Daniel Veillard45490ae2008-07-29 09:13:19 +000010677
Owen Taylor3473f882001-02-23 17:55:21 +000010678 while (NXT(len) != 0) {
10679 if (NXT(len) == '/') {
10680 /* element name */
10681#ifdef DEBUG_STEP
10682 xmlGenericError(xmlGenericErrorContext,
10683 "PathExpr: AbbrRelLocation\n");
10684#endif
10685 lc = 1;
10686 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010687 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010688 /* ignore blanks */
10689 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010690 } else if (NXT(len) == ':') {
10691#ifdef DEBUG_STEP
10692 xmlGenericError(xmlGenericErrorContext,
10693 "PathExpr: AbbrRelLocation\n");
10694#endif
10695 lc = 1;
10696 break;
10697 } else if ((NXT(len) == '(')) {
Nick Wellnhofer9ab01a22016-06-28 14:22:23 +020010698 /* Node Type or Function */
Owen Taylor3473f882001-02-23 17:55:21 +000010699 if (xmlXPathIsNodeType(name)) {
10700#ifdef DEBUG_STEP
10701 xmlGenericError(xmlGenericErrorContext,
10702 "PathExpr: Type search\n");
10703#endif
10704 lc = 1;
Nick Wellnhofer9ab01a22016-06-28 14:22:23 +020010705#ifdef LIBXML_XPTR_ENABLED
10706 } else if (ctxt->xptr &&
10707 xmlStrEqual(name, BAD_CAST "range-to")) {
10708 lc = 1;
10709#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010710 } else {
10711#ifdef DEBUG_STEP
10712 xmlGenericError(xmlGenericErrorContext,
10713 "PathExpr: function call\n");
10714#endif
10715 lc = 0;
10716 }
10717 break;
10718 } else if ((NXT(len) == '[')) {
10719 /* element name */
10720#ifdef DEBUG_STEP
10721 xmlGenericError(xmlGenericErrorContext,
10722 "PathExpr: AbbrRelLocation\n");
10723#endif
10724 lc = 1;
10725 break;
10726 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10727 (NXT(len) == '=')) {
10728 lc = 1;
10729 break;
10730 } else {
10731 lc = 1;
10732 break;
10733 }
10734 len++;
10735 }
10736 if (NXT(len) == 0) {
10737#ifdef DEBUG_STEP
10738 xmlGenericError(xmlGenericErrorContext,
10739 "PathExpr: AbbrRelLocation\n");
10740#endif
10741 /* element name */
10742 lc = 1;
10743 }
10744 xmlFree(name);
10745 } else {
William M. Brack08171912003-12-29 02:52:11 +000010746 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010747 XP_ERROR(XPATH_EXPR_ERROR);
10748 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010749 }
Owen Taylor3473f882001-02-23 17:55:21 +000010750
10751 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010752 if (CUR == '/') {
10753 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10754 } else {
10755 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010756 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010757 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010758 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010759 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010760 CHECK_ERROR;
10761 if ((CUR == '/') && (NXT(1) == '/')) {
10762 SKIP(2);
10763 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010764
10765 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10766 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10767 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10768
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010769 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010770 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010771 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010772 }
10773 }
10774 SKIP_BLANKS;
10775}
10776
10777/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010778 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010779 * @ctxt: the XPath Parser context
10780 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010781 * [18] UnionExpr ::= PathExpr
10782 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010783 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010784 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010785 */
10786
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010787static void
10788xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10789 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010790 CHECK_ERROR;
10791 SKIP_BLANKS;
10792 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010793 int op1 = ctxt->comp->last;
10794 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010795
10796 NEXT;
10797 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010798 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010799
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010800 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10801
Owen Taylor3473f882001-02-23 17:55:21 +000010802 SKIP_BLANKS;
10803 }
Owen Taylor3473f882001-02-23 17:55:21 +000010804}
10805
10806/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010807 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010808 * @ctxt: the XPath Parser context
10809 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010810 * [27] UnaryExpr ::= UnionExpr
10811 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010812 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010813 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010814 */
10815
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010816static void
10817xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010818 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010819 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010820
10821 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010822 while (CUR == '-') {
10823 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010824 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010825 NEXT;
10826 SKIP_BLANKS;
10827 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010828
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010829 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010830 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010831 if (found) {
10832 if (minus)
10833 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10834 else
10835 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010836 }
10837}
10838
10839/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010840 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010841 * @ctxt: the XPath Parser context
10842 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010843 * [26] MultiplicativeExpr ::= UnaryExpr
10844 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10845 * | MultiplicativeExpr 'div' UnaryExpr
10846 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010847 * [34] MultiplyOperator ::= '*'
10848 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010849 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010850 */
10851
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010852static void
10853xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10854 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010855 CHECK_ERROR;
10856 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010857 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010858 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10859 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10860 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010861 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010862
10863 if (CUR == '*') {
10864 op = 0;
10865 NEXT;
10866 } else if (CUR == 'd') {
10867 op = 1;
10868 SKIP(3);
10869 } else if (CUR == 'm') {
10870 op = 2;
10871 SKIP(3);
10872 }
10873 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010874 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010875 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010876 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010877 SKIP_BLANKS;
10878 }
10879}
10880
10881/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010882 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010883 * @ctxt: the XPath Parser context
10884 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010885 * [25] AdditiveExpr ::= MultiplicativeExpr
10886 * | AdditiveExpr '+' MultiplicativeExpr
10887 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010888 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010889 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010890 */
10891
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010892static void
10893xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010894
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010895 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010896 CHECK_ERROR;
10897 SKIP_BLANKS;
10898 while ((CUR == '+') || (CUR == '-')) {
10899 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010900 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010901
10902 if (CUR == '+') plus = 1;
10903 else plus = 0;
10904 NEXT;
10905 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010906 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010907 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010908 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010909 SKIP_BLANKS;
10910 }
10911}
10912
10913/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010914 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010915 * @ctxt: the XPath Parser context
10916 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010917 * [24] RelationalExpr ::= AdditiveExpr
10918 * | RelationalExpr '<' AdditiveExpr
10919 * | RelationalExpr '>' AdditiveExpr
10920 * | RelationalExpr '<=' AdditiveExpr
10921 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010922 *
10923 * A <= B > C is allowed ? Answer from James, yes with
10924 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10925 * which is basically what got implemented.
10926 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010927 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010928 * on the stack
10929 */
10930
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010931static void
10932xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10933 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010934 CHECK_ERROR;
10935 SKIP_BLANKS;
10936 while ((CUR == '<') ||
10937 (CUR == '>') ||
10938 ((CUR == '<') && (NXT(1) == '=')) ||
10939 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010940 int inf, strict;
10941 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010942
10943 if (CUR == '<') inf = 1;
10944 else inf = 0;
10945 if (NXT(1) == '=') strict = 0;
10946 else strict = 1;
10947 NEXT;
10948 if (!strict) NEXT;
10949 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010950 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010951 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010952 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010953 SKIP_BLANKS;
10954 }
10955}
10956
10957/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010958 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010959 * @ctxt: the XPath Parser context
10960 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010961 * [23] EqualityExpr ::= RelationalExpr
10962 * | EqualityExpr '=' RelationalExpr
10963 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010964 *
10965 * A != B != C is allowed ? Answer from James, yes with
10966 * (RelationalExpr = RelationalExpr) = RelationalExpr
10967 * (RelationalExpr != RelationalExpr) != RelationalExpr
10968 * which is basically what got implemented.
10969 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010970 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010971 *
10972 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010973static void
10974xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10975 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010976 CHECK_ERROR;
10977 SKIP_BLANKS;
10978 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010979 int eq;
10980 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010981
10982 if (CUR == '=') eq = 1;
10983 else eq = 0;
10984 NEXT;
10985 if (!eq) NEXT;
10986 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010987 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010988 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010989 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010990 SKIP_BLANKS;
10991 }
10992}
10993
10994/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010995 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010996 * @ctxt: the XPath Parser context
10997 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010998 * [22] AndExpr ::= EqualityExpr
10999 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000011000 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011001 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000011002 *
11003 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011004static void
11005xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11006 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011007 CHECK_ERROR;
11008 SKIP_BLANKS;
11009 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011010 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011011 SKIP(3);
11012 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011013 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011014 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011015 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011016 SKIP_BLANKS;
11017 }
11018}
11019
11020/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000011021 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000011022 * @ctxt: the XPath Parser context
11023 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011024 * [14] Expr ::= OrExpr
11025 * [21] OrExpr ::= AndExpr
11026 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000011027 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011028 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000011029 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011030static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011031xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011032 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011033 CHECK_ERROR;
11034 SKIP_BLANKS;
11035 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011036 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011037 SKIP(2);
11038 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011039 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011040 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011041 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011042 SKIP_BLANKS;
11043 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011044 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011045 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011046 /*
11047 * This is the main place to eliminate sorting for
11048 * operations which don't require a sorted node-set.
11049 * E.g. count().
11050 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011051 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11052 }
Owen Taylor3473f882001-02-23 17:55:21 +000011053}
11054
11055/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011056 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000011057 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011058 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000011059 *
11060 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000011061 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000011062 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011063 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000011064 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011065static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011066xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011067 int op1 = ctxt->comp->last;
11068
11069 SKIP_BLANKS;
11070 if (CUR != '[') {
11071 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11072 }
11073 NEXT;
11074 SKIP_BLANKS;
11075
11076 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011077 /*
11078 * This call to xmlXPathCompileExpr() will deactivate sorting
11079 * of the predicate result.
11080 * TODO: Sorting is still activated for filters, since I'm not
11081 * sure if needed. Normally sorting should not be needed, since
11082 * a filter can only diminish the number of items in a sequence,
11083 * but won't change its order; so if the initial sequence is sorted,
11084 * subsequent sorting is not needed.
11085 */
11086 if (! filter)
11087 xmlXPathCompileExpr(ctxt, 0);
11088 else
11089 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011090 CHECK_ERROR;
11091
11092 if (CUR != ']') {
11093 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11094 }
11095
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011096 if (filter)
11097 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11098 else
11099 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011100
11101 NEXT;
11102 SKIP_BLANKS;
11103}
11104
11105/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011106 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011107 * @ctxt: the XPath Parser context
11108 * @test: pointer to a xmlXPathTestVal
11109 * @type: pointer to a xmlXPathTypeVal
11110 * @prefix: placeholder for a possible name prefix
11111 *
11112 * [7] NodeTest ::= NameTest
11113 * | NodeType '(' ')'
11114 * | 'processing-instruction' '(' Literal ')'
11115 *
11116 * [37] NameTest ::= '*'
11117 * | NCName ':' '*'
11118 * | QName
11119 * [38] NodeType ::= 'comment'
11120 * | 'text'
11121 * | 'processing-instruction'
11122 * | 'node'
11123 *
William M. Brack08171912003-12-29 02:52:11 +000011124 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011125 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011126static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011127xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11128 xmlXPathTypeVal *type, const xmlChar **prefix,
11129 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011130 int blanks;
11131
11132 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11133 STRANGE;
11134 return(NULL);
11135 }
William M. Brack78637da2003-07-31 14:47:38 +000011136 *type = (xmlXPathTypeVal) 0;
11137 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011138 *prefix = NULL;
11139 SKIP_BLANKS;
11140
11141 if ((name == NULL) && (CUR == '*')) {
11142 /*
11143 * All elements
11144 */
11145 NEXT;
11146 *test = NODE_TEST_ALL;
11147 return(NULL);
11148 }
11149
11150 if (name == NULL)
11151 name = xmlXPathParseNCName(ctxt);
11152 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011153 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011154 }
11155
William M. Brack76e95df2003-10-18 16:20:14 +000011156 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011157 SKIP_BLANKS;
11158 if (CUR == '(') {
11159 NEXT;
11160 /*
11161 * NodeType or PI search
11162 */
11163 if (xmlStrEqual(name, BAD_CAST "comment"))
11164 *type = NODE_TYPE_COMMENT;
11165 else if (xmlStrEqual(name, BAD_CAST "node"))
11166 *type = NODE_TYPE_NODE;
11167 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11168 *type = NODE_TYPE_PI;
11169 else if (xmlStrEqual(name, BAD_CAST "text"))
11170 *type = NODE_TYPE_TEXT;
11171 else {
11172 if (name != NULL)
11173 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011174 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011175 }
11176
11177 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011178
Owen Taylor3473f882001-02-23 17:55:21 +000011179 SKIP_BLANKS;
11180 if (*type == NODE_TYPE_PI) {
11181 /*
11182 * Specific case: search a PI by name.
11183 */
Owen Taylor3473f882001-02-23 17:55:21 +000011184 if (name != NULL)
11185 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011186 name = NULL;
11187 if (CUR != ')') {
11188 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011189 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011190 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011191 SKIP_BLANKS;
11192 }
Owen Taylor3473f882001-02-23 17:55:21 +000011193 }
11194 if (CUR != ')') {
11195 if (name != NULL)
11196 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011197 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011198 }
11199 NEXT;
11200 return(name);
11201 }
11202 *test = NODE_TEST_NAME;
11203 if ((!blanks) && (CUR == ':')) {
11204 NEXT;
11205
11206 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011207 * Since currently the parser context don't have a
11208 * namespace list associated:
11209 * The namespace name for this prefix can be computed
11210 * only at evaluation time. The compilation is done
11211 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011212 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011213#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011214 *prefix = xmlXPathNsLookup(ctxt->context, name);
11215 if (name != NULL)
11216 xmlFree(name);
11217 if (*prefix == NULL) {
11218 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11219 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011220#else
11221 *prefix = name;
11222#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011223
11224 if (CUR == '*') {
11225 /*
11226 * All elements
11227 */
11228 NEXT;
11229 *test = NODE_TEST_ALL;
11230 return(NULL);
11231 }
11232
11233 name = xmlXPathParseNCName(ctxt);
11234 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011235 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011236 }
11237 }
11238 return(name);
11239}
11240
11241/**
11242 * xmlXPathIsAxisName:
11243 * @name: a preparsed name token
11244 *
11245 * [6] AxisName ::= 'ancestor'
11246 * | 'ancestor-or-self'
11247 * | 'attribute'
11248 * | 'child'
11249 * | 'descendant'
11250 * | 'descendant-or-self'
11251 * | 'following'
11252 * | 'following-sibling'
11253 * | 'namespace'
11254 * | 'parent'
11255 * | 'preceding'
11256 * | 'preceding-sibling'
11257 * | 'self'
11258 *
11259 * Returns the axis or 0
11260 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011261static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011262xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011263 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011264 switch (name[0]) {
11265 case 'a':
11266 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11267 ret = AXIS_ANCESTOR;
11268 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11269 ret = AXIS_ANCESTOR_OR_SELF;
11270 if (xmlStrEqual(name, BAD_CAST "attribute"))
11271 ret = AXIS_ATTRIBUTE;
11272 break;
11273 case 'c':
11274 if (xmlStrEqual(name, BAD_CAST "child"))
11275 ret = AXIS_CHILD;
11276 break;
11277 case 'd':
11278 if (xmlStrEqual(name, BAD_CAST "descendant"))
11279 ret = AXIS_DESCENDANT;
11280 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11281 ret = AXIS_DESCENDANT_OR_SELF;
11282 break;
11283 case 'f':
11284 if (xmlStrEqual(name, BAD_CAST "following"))
11285 ret = AXIS_FOLLOWING;
11286 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11287 ret = AXIS_FOLLOWING_SIBLING;
11288 break;
11289 case 'n':
11290 if (xmlStrEqual(name, BAD_CAST "namespace"))
11291 ret = AXIS_NAMESPACE;
11292 break;
11293 case 'p':
11294 if (xmlStrEqual(name, BAD_CAST "parent"))
11295 ret = AXIS_PARENT;
11296 if (xmlStrEqual(name, BAD_CAST "preceding"))
11297 ret = AXIS_PRECEDING;
11298 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11299 ret = AXIS_PRECEDING_SIBLING;
11300 break;
11301 case 's':
11302 if (xmlStrEqual(name, BAD_CAST "self"))
11303 ret = AXIS_SELF;
11304 break;
11305 }
11306 return(ret);
11307}
11308
11309/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011310 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011311 * @ctxt: the XPath Parser context
11312 *
11313 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011314 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011315 *
11316 * [12] AbbreviatedStep ::= '.' | '..'
11317 *
11318 * [5] AxisSpecifier ::= AxisName '::'
11319 * | AbbreviatedAxisSpecifier
11320 *
11321 * [13] AbbreviatedAxisSpecifier ::= '@'?
11322 *
11323 * Modified for XPtr range support as:
11324 *
11325 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11326 * | AbbreviatedStep
11327 * | 'range-to' '(' Expr ')' Predicate*
11328 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011329 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011330 * A location step of . is short for self::node(). This is
11331 * particularly useful in conjunction with //. For example, the
11332 * location path .//para is short for
11333 * self::node()/descendant-or-self::node()/child::para
11334 * and so will select all para descendant elements of the context
11335 * node.
11336 * Similarly, a location step of .. is short for parent::node().
11337 * For example, ../title is short for parent::node()/child::title
11338 * and so will select the title children of the parent of the context
11339 * node.
11340 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011341static void
11342xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011343#ifdef LIBXML_XPTR_ENABLED
11344 int rangeto = 0;
11345 int op2 = -1;
11346#endif
11347
Owen Taylor3473f882001-02-23 17:55:21 +000011348 SKIP_BLANKS;
11349 if ((CUR == '.') && (NXT(1) == '.')) {
11350 SKIP(2);
11351 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011352 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11353 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011354 } else if (CUR == '.') {
11355 NEXT;
11356 SKIP_BLANKS;
11357 } else {
11358 xmlChar *name = NULL;
11359 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011360 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011361 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011362 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011363 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011364
11365 /*
11366 * The modification needed for XPointer change to the production
11367 */
11368#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011369 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011370 name = xmlXPathParseNCName(ctxt);
11371 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011372 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011373 xmlFree(name);
11374 SKIP_BLANKS;
11375 if (CUR != '(') {
11376 XP_ERROR(XPATH_EXPR_ERROR);
11377 }
11378 NEXT;
11379 SKIP_BLANKS;
11380
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011381 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011382 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011383 CHECK_ERROR;
11384
11385 SKIP_BLANKS;
11386 if (CUR != ')') {
11387 XP_ERROR(XPATH_EXPR_ERROR);
11388 }
11389 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011390 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011391 goto eval_predicates;
11392 }
11393 }
11394#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011395 if (CUR == '*') {
11396 axis = AXIS_CHILD;
11397 } else {
11398 if (name == NULL)
11399 name = xmlXPathParseNCName(ctxt);
11400 if (name != NULL) {
11401 axis = xmlXPathIsAxisName(name);
11402 if (axis != 0) {
11403 SKIP_BLANKS;
11404 if ((CUR == ':') && (NXT(1) == ':')) {
11405 SKIP(2);
11406 xmlFree(name);
11407 name = NULL;
11408 } else {
11409 /* an element name can conflict with an axis one :-\ */
11410 axis = AXIS_CHILD;
11411 }
Owen Taylor3473f882001-02-23 17:55:21 +000011412 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011413 axis = AXIS_CHILD;
11414 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011415 } else if (CUR == '@') {
11416 NEXT;
11417 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011418 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011419 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011420 }
Owen Taylor3473f882001-02-23 17:55:21 +000011421 }
11422
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011423 if (ctxt->error != XPATH_EXPRESSION_OK) {
11424 xmlFree(name);
11425 return;
11426 }
Owen Taylor3473f882001-02-23 17:55:21 +000011427
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011428 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011429 if (test == 0)
11430 return;
11431
Daniel Veillarded6c5492005-07-23 15:00:22 +000011432 if ((prefix != NULL) && (ctxt->context != NULL) &&
11433 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11434 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11435 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11436 }
11437 }
Owen Taylor3473f882001-02-23 17:55:21 +000011438#ifdef DEBUG_STEP
11439 xmlGenericError(xmlGenericErrorContext,
11440 "Basis : computing new set\n");
11441#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011442
Owen Taylor3473f882001-02-23 17:55:21 +000011443#ifdef DEBUG_STEP
11444 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011445 if (ctxt->value == NULL)
11446 xmlGenericError(xmlGenericErrorContext, "no value\n");
11447 else if (ctxt->value->nodesetval == NULL)
11448 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11449 else
11450 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011451#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011452
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011453#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011454eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011455#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011456 op1 = ctxt->comp->last;
11457 ctxt->comp->last = -1;
11458
Owen Taylor3473f882001-02-23 17:55:21 +000011459 SKIP_BLANKS;
11460 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011461 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011462 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011463
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011464#ifdef LIBXML_XPTR_ENABLED
11465 if (rangeto) {
11466 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11467 } else
11468#endif
11469 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11470 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011471
Owen Taylor3473f882001-02-23 17:55:21 +000011472 }
11473#ifdef DEBUG_STEP
11474 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011475 if (ctxt->value == NULL)
11476 xmlGenericError(xmlGenericErrorContext, "no value\n");
11477 else if (ctxt->value->nodesetval == NULL)
11478 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11479 else
11480 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11481 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011482#endif
11483}
11484
11485/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011486 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011487 * @ctxt: the XPath Parser context
11488 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011489 * [3] RelativeLocationPath ::= Step
11490 * | RelativeLocationPath '/' Step
11491 * | AbbreviatedRelativeLocationPath
11492 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011493 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011494 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011495 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011496static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011497xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011498(xmlXPathParserContextPtr ctxt) {
11499 SKIP_BLANKS;
11500 if ((CUR == '/') && (NXT(1) == '/')) {
11501 SKIP(2);
11502 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011503 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11504 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011505 } else if (CUR == '/') {
11506 NEXT;
11507 SKIP_BLANKS;
11508 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011509 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011510 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011511 SKIP_BLANKS;
11512 while (CUR == '/') {
11513 if ((CUR == '/') && (NXT(1) == '/')) {
11514 SKIP(2);
11515 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011516 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011517 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011518 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011519 } else if (CUR == '/') {
11520 NEXT;
11521 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011522 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011523 }
11524 SKIP_BLANKS;
11525 }
11526}
11527
11528/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011529 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011530 * @ctxt: the XPath Parser context
11531 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011532 * [1] LocationPath ::= RelativeLocationPath
11533 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011534 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011535 * | AbbreviatedAbsoluteLocationPath
11536 * [10] AbbreviatedAbsoluteLocationPath ::=
11537 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011538 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011539 * Compile a location path
11540 *
Owen Taylor3473f882001-02-23 17:55:21 +000011541 * // is short for /descendant-or-self::node()/. For example,
11542 * //para is short for /descendant-or-self::node()/child::para and
11543 * so will select any para element in the document (even a para element
11544 * that is a document element will be selected by //para since the
11545 * document element node is a child of the root node); div//para is
11546 * short for div/descendant-or-self::node()/child::para and so will
11547 * select all para descendants of div children.
11548 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011549static void
11550xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011551 SKIP_BLANKS;
11552 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011553 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011554 } else {
11555 while (CUR == '/') {
11556 if ((CUR == '/') && (NXT(1) == '/')) {
11557 SKIP(2);
11558 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011559 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11560 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011561 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011562 } else if (CUR == '/') {
11563 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011564 SKIP_BLANKS;
11565 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011566 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011567 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011568 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011569 }
Martin729601f2009-10-12 22:42:26 +020011570 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011571 }
11572 }
11573}
11574
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011575/************************************************************************
11576 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011577 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011578 * *
11579 ************************************************************************/
11580
Daniel Veillardf06307e2001-07-03 10:35:50 +000011581static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011582xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11583
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011584#ifdef DEBUG_STEP
11585static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011586xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011587 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011588{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011589 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011590 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011591 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011592 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011593 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011594 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011595 xmlGenericError(xmlGenericErrorContext,
11596 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011597 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011598 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011599 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011600 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011601 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011602 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011603 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011604 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011605 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011606 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011607 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011608 xmlGenericError(xmlGenericErrorContext,
11609 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011610 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011611 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011612 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011613 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011614 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011615 xmlGenericError(xmlGenericErrorContext,
11616 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011617 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011618 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011619 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011620 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011621 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011622 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011623 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011624 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011625 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011626 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011627 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011628 xmlGenericError(xmlGenericErrorContext,
11629 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011630 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011631 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011632 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011633 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011634 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011635 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011636 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011637 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011638 case NODE_TEST_NONE:
11639 xmlGenericError(xmlGenericErrorContext,
11640 " searching for none !!!\n");
11641 break;
11642 case NODE_TEST_TYPE:
11643 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011644 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011645 break;
11646 case NODE_TEST_PI:
11647 xmlGenericError(xmlGenericErrorContext,
11648 " searching for PI !!!\n");
11649 break;
11650 case NODE_TEST_ALL:
11651 xmlGenericError(xmlGenericErrorContext,
11652 " searching for *\n");
11653 break;
11654 case NODE_TEST_NS:
11655 xmlGenericError(xmlGenericErrorContext,
11656 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011657 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011658 break;
11659 case NODE_TEST_NAME:
11660 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011661 " searching for name %s\n", op->value5);
11662 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011663 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011664 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011665 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011666 }
11667 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011668}
11669#endif /* DEBUG_STEP */
11670
11671static int
11672xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11673 xmlXPathStepOpPtr op,
11674 xmlNodeSetPtr set,
11675 int contextSize,
11676 int hasNsNodes)
11677{
11678 if (op->ch1 != -1) {
11679 xmlXPathCompExprPtr comp = ctxt->comp;
11680 /*
11681 * Process inner predicates first.
11682 */
11683 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11684 /*
11685 * TODO: raise an internal error.
11686 */
11687 }
11688 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11689 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11690 CHECK_ERROR0;
11691 if (contextSize <= 0)
11692 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011693 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011694 if (op->ch2 != -1) {
11695 xmlXPathContextPtr xpctxt = ctxt->context;
11696 xmlNodePtr contextNode, oldContextNode;
11697 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011698 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011699 xmlXPathStepOpPtr exprOp;
11700 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11701
11702#ifdef LIBXML_XPTR_ENABLED
11703 /*
11704 * URGENT TODO: Check the following:
11705 * We don't expect location sets if evaluating prediates, right?
11706 * Only filters should expect location sets, right?
11707 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011708#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011709 /*
11710 * SPEC XPath 1.0:
11711 * "For each node in the node-set to be filtered, the
11712 * PredicateExpr is evaluated with that node as the
11713 * context node, with the number of nodes in the
11714 * node-set as the context size, and with the proximity
11715 * position of the node in the node-set with respect to
11716 * the axis as the context position;"
11717 * @oldset is the node-set" to be filtered.
11718 *
11719 * SPEC XPath 1.0:
11720 * "only predicates change the context position and
11721 * context size (see [2.4 Predicates])."
11722 * Example:
11723 * node-set context pos
11724 * nA 1
11725 * nB 2
11726 * nC 3
11727 * After applying predicate [position() > 1] :
11728 * node-set context pos
11729 * nB 1
11730 * nC 2
11731 */
11732 oldContextNode = xpctxt->node;
11733 oldContextDoc = xpctxt->doc;
11734 /*
11735 * Get the expression of this predicate.
11736 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011737 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011738 newContextSize = 0;
11739 for (i = 0; i < set->nodeNr; i++) {
11740 if (set->nodeTab[i] == NULL)
11741 continue;
11742
11743 contextNode = set->nodeTab[i];
11744 xpctxt->node = contextNode;
11745 xpctxt->contextSize = contextSize;
11746 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011747
11748 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011749 * Also set the xpath document in case things like
11750 * key() are evaluated in the predicate.
11751 */
11752 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11753 (contextNode->doc != NULL))
11754 xpctxt->doc = contextNode->doc;
11755 /*
11756 * Evaluate the predicate expression with 1 context node
11757 * at a time; this node is packaged into a node set; this
11758 * node set is handed over to the evaluation mechanism.
11759 */
11760 if (contextObj == NULL)
11761 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011762 else {
11763 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11764 contextNode) < 0) {
11765 ctxt->error = XPATH_MEMORY_ERROR;
11766 goto evaluation_exit;
11767 }
11768 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011769
11770 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011771
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011772 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011773
William M. Brack0bcec062007-02-14 02:15:19 +000011774 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11775 xmlXPathNodeSetClear(set, hasNsNodes);
11776 newContextSize = 0;
11777 goto evaluation_exit;
11778 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011779
11780 if (res != 0) {
11781 newContextSize++;
11782 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011783 /*
11784 * Remove the entry from the initial node set.
11785 */
11786 set->nodeTab[i] = NULL;
11787 if (contextNode->type == XML_NAMESPACE_DECL)
11788 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011789 }
11790 if (ctxt->value == contextObj) {
11791 /*
11792 * Don't free the temporary XPath object holding the
11793 * context node, in order to avoid massive recreation
11794 * inside this loop.
11795 */
11796 valuePop(ctxt);
11797 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11798 } else {
11799 /*
11800 * TODO: The object was lost in the evaluation machinery.
11801 * Can this happen? Maybe in internal-error cases.
11802 */
11803 contextObj = NULL;
11804 }
11805 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011806
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011807 if (contextObj != NULL) {
11808 if (ctxt->value == contextObj)
11809 valuePop(ctxt);
11810 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011811 }
William M. Brack0bcec062007-02-14 02:15:19 +000011812evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011813 if (exprRes != NULL)
11814 xmlXPathReleaseObject(ctxt->context, exprRes);
11815 /*
11816 * Reset/invalidate the context.
11817 */
11818 xpctxt->node = oldContextNode;
11819 xpctxt->doc = oldContextDoc;
11820 xpctxt->contextSize = -1;
11821 xpctxt->proximityPosition = -1;
11822 return(newContextSize);
11823 }
11824 return(contextSize);
11825}
11826
11827static int
11828xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11829 xmlXPathStepOpPtr op,
11830 xmlNodeSetPtr set,
11831 int contextSize,
11832 int minPos,
11833 int maxPos,
11834 int hasNsNodes)
11835{
11836 if (op->ch1 != -1) {
11837 xmlXPathCompExprPtr comp = ctxt->comp;
11838 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11839 /*
11840 * TODO: raise an internal error.
11841 */
11842 }
11843 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11844 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11845 CHECK_ERROR0;
11846 if (contextSize <= 0)
11847 return(0);
11848 }
11849 /*
11850 * Check if the node set contains a sufficient number of nodes for
11851 * the requested range.
11852 */
11853 if (contextSize < minPos) {
11854 xmlXPathNodeSetClear(set, hasNsNodes);
11855 return(0);
11856 }
11857 if (op->ch2 == -1) {
11858 /*
11859 * TODO: Can this ever happen?
11860 */
11861 return (contextSize);
11862 } else {
11863 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011864 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011865 xmlXPathStepOpPtr exprOp;
11866 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11867 xmlNodePtr oldContextNode, contextNode = NULL;
11868 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011869 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011870
11871#ifdef LIBXML_XPTR_ENABLED
11872 /*
11873 * URGENT TODO: Check the following:
11874 * We don't expect location sets if evaluating prediates, right?
11875 * Only filters should expect location sets, right?
11876 */
11877#endif /* LIBXML_XPTR_ENABLED */
11878
11879 /*
11880 * Save old context.
11881 */
11882 oldContextNode = xpctxt->node;
11883 oldContextDoc = xpctxt->doc;
11884 /*
11885 * Get the expression of this predicate.
11886 */
11887 exprOp = &ctxt->comp->steps[op->ch2];
11888 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011889 xmlXPathObjectPtr tmp;
11890
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011891 if (set->nodeTab[i] == NULL)
11892 continue;
11893
11894 contextNode = set->nodeTab[i];
11895 xpctxt->node = contextNode;
11896 xpctxt->contextSize = contextSize;
11897 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011898
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011899 /*
11900 * Initialize the new set.
11901 * Also set the xpath document in case things like
11902 * key() evaluation are attempted on the predicate
11903 */
11904 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11905 (contextNode->doc != NULL))
11906 xpctxt->doc = contextNode->doc;
11907 /*
11908 * Evaluate the predicate expression with 1 context node
11909 * at a time; this node is packaged into a node set; this
11910 * node set is handed over to the evaluation mechanism.
11911 */
11912 if (contextObj == NULL)
11913 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011914 else {
11915 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11916 contextNode) < 0) {
11917 ctxt->error = XPATH_MEMORY_ERROR;
11918 goto evaluation_exit;
11919 }
11920 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011921
Daniel Veillardf5048b32011-08-18 17:10:13 +080011922 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011923 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011924 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011925 tmp = valuePop(ctxt);
11926 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011927
William M. Brackf1794562007-08-23 12:58:13 +000011928 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011929 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011930 /*
11931 * Free up the result
11932 * then pop off contextObj, which will be freed later
11933 */
11934 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011935 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011936 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011937 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011938 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011939 /* push the result back onto the stack */
11940 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011941
11942 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011943 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011944
11945 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011946 /*
11947 * Fits in the requested range.
11948 */
11949 newContextSize++;
11950 if (minPos == maxPos) {
11951 /*
11952 * Only 1 node was requested.
11953 */
11954 if (contextNode->type == XML_NAMESPACE_DECL) {
11955 /*
11956 * As always: take care of those nasty
11957 * namespace nodes.
11958 */
11959 set->nodeTab[i] = NULL;
11960 }
11961 xmlXPathNodeSetClear(set, hasNsNodes);
11962 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011963 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011964 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011965 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011966 if (pos == maxPos) {
11967 /*
11968 * We are done.
11969 */
11970 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11971 goto evaluation_exit;
11972 }
11973 } else {
11974 /*
11975 * Remove the entry from the initial node set.
11976 */
11977 set->nodeTab[i] = NULL;
11978 if (contextNode->type == XML_NAMESPACE_DECL)
11979 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11980 }
11981 if (exprRes != NULL) {
11982 xmlXPathReleaseObject(ctxt->context, exprRes);
11983 exprRes = NULL;
11984 }
11985 if (ctxt->value == contextObj) {
11986 /*
11987 * Don't free the temporary XPath object holding the
11988 * context node, in order to avoid massive recreation
11989 * inside this loop.
11990 */
11991 valuePop(ctxt);
11992 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11993 } else {
11994 /*
11995 * The object was lost in the evaluation machinery.
11996 * Can this happen? Maybe in case of internal-errors.
11997 */
11998 contextObj = NULL;
11999 }
12000 }
12001 goto evaluation_exit;
12002
12003evaluation_error:
12004 xmlXPathNodeSetClear(set, hasNsNodes);
12005 newContextSize = 0;
12006
12007evaluation_exit:
12008 if (contextObj != NULL) {
12009 if (ctxt->value == contextObj)
12010 valuePop(ctxt);
12011 xmlXPathReleaseObject(xpctxt, contextObj);
12012 }
12013 if (exprRes != NULL)
12014 xmlXPathReleaseObject(ctxt->context, exprRes);
12015 /*
12016 * Reset/invalidate the context.
12017 */
12018 xpctxt->node = oldContextNode;
12019 xpctxt->doc = oldContextDoc;
12020 xpctxt->contextSize = -1;
12021 xpctxt->proximityPosition = -1;
12022 return(newContextSize);
12023 }
12024 return(contextSize);
12025}
12026
12027static int
12028xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000012029 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012030 int *maxPos)
12031{
12032
12033 xmlXPathStepOpPtr exprOp;
12034
12035 /*
12036 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12037 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012038
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012039 /*
12040 * If not -1, then ch1 will point to:
12041 * 1) For predicates (XPATH_OP_PREDICATE):
12042 * - an inner predicate operator
12043 * 2) For filters (XPATH_OP_FILTER):
12044 * - an inner filter operater OR
12045 * - an expression selecting the node set.
12046 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012047 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012048 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12049 return(0);
12050
12051 if (op->ch2 != -1) {
12052 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012053 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012054 return(0);
12055
12056 if ((exprOp != NULL) &&
12057 (exprOp->op == XPATH_OP_VALUE) &&
12058 (exprOp->value4 != NULL) &&
12059 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12060 {
Nick Wellnhofera58331a2017-05-29 21:02:21 +020012061 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12062
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012063 /*
12064 * We have a "[n]" predicate here.
12065 * TODO: Unfortunately this simplistic test here is not
12066 * able to detect a position() predicate in compound
12067 * expressions like "[@attr = 'a" and position() = 1],
12068 * and even not the usage of position() in
12069 * "[position() = 1]"; thus - obviously - a position-range,
12070 * like it "[position() < 5]", is also not detected.
12071 * Maybe we could rewrite the AST to ease the optimization.
12072 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012073
Nick Wellnhofera58331a2017-05-29 21:02:21 +020012074 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12075 *maxPos = (int) floatval;
12076 if (floatval == (double) *maxPos)
12077 return(1);
12078 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012079 }
12080 return(0);
12081}
12082
12083static int
12084xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12085 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012086 xmlNodePtr * first, xmlNodePtr * last,
12087 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012088{
12089
12090#define XP_TEST_HIT \
12091 if (hasAxisRange != 0) { \
12092 if (++pos == maxPos) { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012093 if (addNode(seq, cur) < 0) \
12094 ctxt->error = XPATH_MEMORY_ERROR; \
12095 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012096 } else { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012097 if (addNode(seq, cur) < 0) \
12098 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012099 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012100
12101#define XP_TEST_HIT_NS \
12102 if (hasAxisRange != 0) { \
12103 if (++pos == maxPos) { \
12104 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012105 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12106 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012107 goto axis_range_end; } \
12108 } else { \
12109 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012110 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12111 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012112 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012113
12114 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12115 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12116 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12117 const xmlChar *prefix = op->value4;
12118 const xmlChar *name = op->value5;
12119 const xmlChar *URI = NULL;
12120
12121#ifdef DEBUG_STEP
12122 int nbMatches = 0, prevMatches = 0;
12123#endif
12124 int total = 0, hasNsNodes = 0;
12125 /* The popped object holding the context nodes */
12126 xmlXPathObjectPtr obj;
12127 /* The set of context nodes for the node tests */
12128 xmlNodeSetPtr contextSeq;
12129 int contextIdx;
12130 xmlNodePtr contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012131 /* The final resulting node set wrt to all context nodes */
12132 xmlNodeSetPtr outSeq;
12133 /*
12134 * The temporary resulting node set wrt 1 context node.
12135 * Used to feed predicate evaluation.
12136 */
12137 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012138 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012139 /* First predicate operator */
12140 xmlXPathStepOpPtr predOp;
12141 int maxPos; /* The requested position() (when a "[n]" predicate) */
12142 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012143 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012144
12145 xmlXPathTraversalFunction next = NULL;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012146 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012147 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012148 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012149 xmlXPathContextPtr xpctxt = ctxt->context;
12150
12151
12152 CHECK_TYPE0(XPATH_NODESET);
12153 obj = valuePop(ctxt);
12154 /*
12155 * Setup namespaces.
12156 */
12157 if (prefix != NULL) {
12158 URI = xmlXPathNsLookup(xpctxt, prefix);
12159 if (URI == NULL) {
12160 xmlXPathReleaseObject(xpctxt, obj);
12161 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12162 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012163 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012164 /*
12165 * Setup axis.
12166 *
12167 * MAYBE FUTURE TODO: merging optimizations:
12168 * - If the nodes to be traversed wrt to the initial nodes and
12169 * the current axis cannot overlap, then we could avoid searching
12170 * for duplicates during the merge.
12171 * But the question is how/when to evaluate if they cannot overlap.
12172 * Example: if we know that for two initial nodes, the one is
12173 * not in the ancestor-or-self axis of the other, then we could safely
12174 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12175 * the descendant-or-self axis.
12176 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012177 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12178 switch (axis) {
12179 case AXIS_ANCESTOR:
12180 first = NULL;
12181 next = xmlXPathNextAncestor;
12182 break;
12183 case AXIS_ANCESTOR_OR_SELF:
12184 first = NULL;
12185 next = xmlXPathNextAncestorOrSelf;
12186 break;
12187 case AXIS_ATTRIBUTE:
12188 first = NULL;
12189 last = NULL;
12190 next = xmlXPathNextAttribute;
12191 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12192 break;
12193 case AXIS_CHILD:
12194 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012195 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12196 (type == NODE_TYPE_NODE))
12197 {
12198 /*
12199 * Optimization if an element node type is 'element'.
12200 */
12201 next = xmlXPathNextChildElement;
12202 } else
12203 next = xmlXPathNextChild;
12204 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12205 break;
12206 case AXIS_DESCENDANT:
12207 last = NULL;
12208 next = xmlXPathNextDescendant;
12209 break;
12210 case AXIS_DESCENDANT_OR_SELF:
12211 last = NULL;
12212 next = xmlXPathNextDescendantOrSelf;
12213 break;
12214 case AXIS_FOLLOWING:
12215 last = NULL;
12216 next = xmlXPathNextFollowing;
12217 break;
12218 case AXIS_FOLLOWING_SIBLING:
12219 last = NULL;
12220 next = xmlXPathNextFollowingSibling;
12221 break;
12222 case AXIS_NAMESPACE:
12223 first = NULL;
12224 last = NULL;
12225 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12226 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12227 break;
12228 case AXIS_PARENT:
12229 first = NULL;
12230 next = xmlXPathNextParent;
12231 break;
12232 case AXIS_PRECEDING:
12233 first = NULL;
12234 next = xmlXPathNextPrecedingInternal;
12235 break;
12236 case AXIS_PRECEDING_SIBLING:
12237 first = NULL;
12238 next = xmlXPathNextPrecedingSibling;
12239 break;
12240 case AXIS_SELF:
12241 first = NULL;
12242 last = NULL;
12243 next = xmlXPathNextSelf;
12244 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12245 break;
12246 }
12247
12248#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012249 xmlXPathDebugDumpStepAxis(op,
12250 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012251#endif
12252
12253 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012254 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012255 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012256 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012257 contextSeq = obj->nodesetval;
12258 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12259 xmlXPathReleaseObject(xpctxt, obj);
12260 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12261 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012262 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012263 /*
12264 * Predicate optimization ---------------------------------------------
12265 * If this step has a last predicate, which contains a position(),
12266 * then we'll optimize (although not exactly "position()", but only
12267 * the short-hand form, i.e., "[n]".
12268 *
12269 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012270 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012271 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12272 * ROOT -- op->ch1
12273 * PREDICATE -- op->ch2 (predOp)
12274 * PREDICATE -- predOp->ch1 = [parent::bar]
12275 * SORT
12276 * COLLECT 'parent' 'name' 'node' bar
12277 * NODE
12278 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12279 *
12280 */
12281 maxPos = 0;
12282 predOp = NULL;
12283 hasPredicateRange = 0;
12284 hasAxisRange = 0;
12285 if (op->ch2 != -1) {
12286 /*
12287 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12288 */
12289 predOp = &ctxt->comp->steps[op->ch2];
12290 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12291 if (predOp->ch1 != -1) {
12292 /*
12293 * Use the next inner predicate operator.
12294 */
12295 predOp = &ctxt->comp->steps[predOp->ch1];
12296 hasPredicateRange = 1;
12297 } else {
12298 /*
12299 * There's no other predicate than the [n] predicate.
12300 */
12301 predOp = NULL;
12302 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012303 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012304 }
12305 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012306 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012307 /*
12308 * Axis traversal -----------------------------------------------------
12309 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012310 /*
12311 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012312 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012313 * - For the namespace axis, the principal node type is namespace.
12314 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012315 *
12316 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012317 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012318 * select all element children of the context node
12319 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012320 oldContextNode = xpctxt->node;
12321 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012322 outSeq = NULL;
12323 seq = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012324 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012325 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012326
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012327
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012328 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12329 (ctxt->error == XPATH_EXPRESSION_OK)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012330 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012331
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012332 if (seq == NULL) {
12333 seq = xmlXPathNodeSetCreate(NULL);
12334 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012335 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012336 goto error;
12337 }
12338 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012339 /*
12340 * Traverse the axis and test the nodes.
12341 */
12342 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012343 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012344 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012345 do {
12346 cur = next(ctxt, cur);
12347 if (cur == NULL)
12348 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012349
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012350 /*
12351 * QUESTION TODO: What does the "first" and "last" stuff do?
12352 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012353 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012354 if (*first == cur)
12355 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012356 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012357#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012358 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012359#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012360 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012361#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012362 {
12363 break;
12364 }
12365 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012366 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012367 if (*last == cur)
12368 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012369 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012370#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012371 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012372#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012373 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012374#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012375 {
12376 break;
12377 }
12378 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012379
12380 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012381
Daniel Veillardf06307e2001-07-03 10:35:50 +000012382#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012383 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12384#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012385
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012386 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012387 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012388 total = 0;
12389 STRANGE
12390 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012391 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012392 if (type == NODE_TYPE_NODE) {
12393 switch (cur->type) {
12394 case XML_DOCUMENT_NODE:
12395 case XML_HTML_DOCUMENT_NODE:
12396#ifdef LIBXML_DOCB_ENABLED
12397 case XML_DOCB_DOCUMENT_NODE:
12398#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012399 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012400 case XML_ATTRIBUTE_NODE:
12401 case XML_PI_NODE:
12402 case XML_COMMENT_NODE:
12403 case XML_CDATA_SECTION_NODE:
12404 case XML_TEXT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012405 XP_TEST_HIT
12406 break;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012407 case XML_NAMESPACE_DECL: {
12408 if (axis == AXIS_NAMESPACE) {
12409 XP_TEST_HIT_NS
12410 } else {
Nick Wellnhofer6eb08942016-05-05 16:49:00 +020012411 hasNsNodes = 1;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012412 XP_TEST_HIT
12413 }
12414 break;
12415 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012416 default:
12417 break;
12418 }
12419 } else if (cur->type == type) {
Daniel Veillard713434d2012-09-26 10:21:06 +080012420 if (cur->type == XML_NAMESPACE_DECL)
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012421 XP_TEST_HIT_NS
12422 else
12423 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012424 } else if ((type == NODE_TYPE_TEXT) &&
12425 (cur->type == XML_CDATA_SECTION_NODE))
12426 {
12427 XP_TEST_HIT
12428 }
12429 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012430 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012431 if ((cur->type == XML_PI_NODE) &&
12432 ((name == NULL) || xmlStrEqual(name, cur->name)))
12433 {
12434 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012435 }
12436 break;
12437 case NODE_TEST_ALL:
12438 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012439 if (cur->type == XML_ATTRIBUTE_NODE)
12440 {
Nick Wellnhofere8de99f2013-08-05 01:26:25 +020012441 if (prefix == NULL)
12442 {
12443 XP_TEST_HIT
12444 } else if ((cur->ns != NULL) &&
12445 (xmlStrEqual(URI, cur->ns->href)))
12446 {
12447 XP_TEST_HIT
12448 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012449 }
12450 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012451 if (cur->type == XML_NAMESPACE_DECL)
12452 {
12453 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012454 }
12455 } else {
12456 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012457 if (prefix == NULL)
12458 {
12459 XP_TEST_HIT
12460
Daniel Veillardf06307e2001-07-03 10:35:50 +000012461 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012462 (xmlStrEqual(URI, cur->ns->href)))
12463 {
12464 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012465 }
12466 }
12467 }
12468 break;
12469 case NODE_TEST_NS:{
12470 TODO;
12471 break;
12472 }
12473 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012474 if (axis == AXIS_ATTRIBUTE) {
12475 if (cur->type != XML_ATTRIBUTE_NODE)
12476 break;
12477 } else if (axis == AXIS_NAMESPACE) {
12478 if (cur->type != XML_NAMESPACE_DECL)
12479 break;
12480 } else {
12481 if (cur->type != XML_ELEMENT_NODE)
12482 break;
12483 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012484 switch (cur->type) {
12485 case XML_ELEMENT_NODE:
12486 if (xmlStrEqual(name, cur->name)) {
12487 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012488 if (cur->ns == NULL)
12489 {
12490 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012491 }
12492 } else {
12493 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012494 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012495 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012496 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012497 }
12498 }
12499 }
12500 break;
12501 case XML_ATTRIBUTE_NODE:{
12502 xmlAttrPtr attr = (xmlAttrPtr) cur;
12503
12504 if (xmlStrEqual(name, attr->name)) {
12505 if (prefix == NULL) {
12506 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012507 (attr->ns->prefix == NULL))
12508 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012509 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012510 }
12511 } else {
12512 if ((attr->ns != NULL) &&
12513 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012514 attr->ns->href)))
12515 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012516 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012517 }
12518 }
12519 }
12520 break;
12521 }
12522 case XML_NAMESPACE_DECL:
12523 if (cur->type == XML_NAMESPACE_DECL) {
12524 xmlNsPtr ns = (xmlNsPtr) cur;
12525
12526 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012527 && (xmlStrEqual(ns->prefix, name)))
12528 {
12529 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012530 }
12531 }
12532 break;
12533 default:
12534 break;
12535 }
12536 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012537 } /* switch(test) */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012538 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012539
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012540 goto apply_predicates;
12541
Daniel Veillard45490ae2008-07-29 09:13:19 +000012542axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012543 /*
12544 * We have a "/foo[n]", and position() = n was reached.
12545 * Note that we can have as well "/foo/::parent::foo[1]", so
12546 * a duplicate-aware merge is still needed.
12547 * Merge with the result.
12548 */
12549 if (outSeq == NULL) {
12550 outSeq = seq;
12551 seq = NULL;
12552 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012553 outSeq = mergeAndClear(outSeq, seq, 0);
12554 /*
12555 * Break if only a true/false result was requested.
12556 */
12557 if (toBool)
12558 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012559 continue;
12560
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012561first_hit: /* ---------------------------------------------------------- */
12562 /*
12563 * Break if only a true/false result was requested and
12564 * no predicates existed and a node test succeeded.
12565 */
12566 if (outSeq == NULL) {
12567 outSeq = seq;
12568 seq = NULL;
12569 } else
12570 outSeq = mergeAndClear(outSeq, seq, 0);
12571 break;
12572
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012573#ifdef DEBUG_STEP
12574 if (seq != NULL)
12575 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012576#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012577
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012578apply_predicates: /* --------------------------------------------------- */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012579 if (ctxt->error != XPATH_EXPRESSION_OK)
12580 goto error;
12581
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012582 /*
12583 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012584 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012585 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12586 /*
12587 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012588 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012589 /*
12590 * QUESTION TODO: The old predicate evaluation took into
12591 * account location-sets.
12592 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12593 * Do we expect such a set here?
12594 * All what I learned now from the evaluation semantics
12595 * does not indicate that a location-set will be processed
12596 * here, so this looks OK.
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012597 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012598 /*
12599 * Iterate over all predicates, starting with the outermost
12600 * predicate.
12601 * TODO: Problem: we cannot execute the inner predicates first
12602 * since we cannot go back *up* the operator tree!
12603 * Options we have:
12604 * 1) Use of recursive functions (like is it currently done
12605 * via xmlXPathCompOpEval())
12606 * 2) Add a predicate evaluation information stack to the
12607 * context struct
12608 * 3) Change the way the operators are linked; we need a
12609 * "parent" field on xmlXPathStepOp
12610 *
12611 * For the moment, I'll try to solve this with a recursive
12612 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012613 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012614 size = seq->nodeNr;
12615 if (hasPredicateRange != 0)
12616 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12617 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12618 else
12619 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12620 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012621
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012622 if (ctxt->error != XPATH_EXPRESSION_OK) {
12623 total = 0;
12624 goto error;
12625 }
12626 /*
12627 * Add the filtered set of nodes to the result node set.
12628 */
12629 if (newSize == 0) {
12630 /*
12631 * The predicates filtered all nodes out.
12632 */
12633 xmlXPathNodeSetClear(seq, hasNsNodes);
12634 } else if (seq->nodeNr > 0) {
12635 /*
12636 * Add to result set.
12637 */
12638 if (outSeq == NULL) {
12639 if (size != newSize) {
12640 /*
12641 * We need to merge and clear here, since
12642 * the sequence will contained NULLed entries.
12643 */
12644 outSeq = mergeAndClear(NULL, seq, 1);
12645 } else {
12646 outSeq = seq;
12647 seq = NULL;
12648 }
12649 } else
12650 outSeq = mergeAndClear(outSeq, seq,
12651 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012652 /*
12653 * Break if only a true/false result was requested.
12654 */
12655 if (toBool)
12656 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012657 }
12658 } else if (seq->nodeNr > 0) {
12659 /*
12660 * Add to result set.
12661 */
12662 if (outSeq == NULL) {
12663 outSeq = seq;
12664 seq = NULL;
12665 } else {
12666 outSeq = mergeAndClear(outSeq, seq, 0);
12667 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012668 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012669 }
12670
12671error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012672 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012673 /*
12674 * QUESTION TODO: What does this do and why?
12675 * TODO: Do we have to do this also for the "error"
12676 * cleanup further down?
12677 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012678 ctxt->value->boolval = 1;
12679 ctxt->value->user = obj->user;
12680 obj->user = NULL;
12681 obj->boolval = 0;
12682 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012683 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012684
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012685 /*
12686 * Ensure we return at least an emtpy set.
12687 */
12688 if (outSeq == NULL) {
12689 if ((seq != NULL) && (seq->nodeNr == 0))
12690 outSeq = seq;
12691 else
12692 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012693 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012694 }
12695 if ((seq != NULL) && (seq != outSeq)) {
12696 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012697 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012698 /*
12699 * Hand over the result. Better to push the set also in
12700 * case of errors.
12701 */
12702 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12703 /*
12704 * Reset the context node.
12705 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012706 xpctxt->node = oldContextNode;
Nick Wellnhofer82b73032016-04-30 17:53:10 +020012707 /*
12708 * When traversing the namespace axis in "toBool" mode, it's
12709 * possible that tmpNsList wasn't freed.
12710 */
12711 if (xpctxt->tmpNsList != NULL) {
12712 xmlFree(xpctxt->tmpNsList);
12713 xpctxt->tmpNsList = NULL;
12714 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012715
12716#ifdef DEBUG_STEP
12717 xmlGenericError(xmlGenericErrorContext,
12718 "\nExamined %d nodes, found %d nodes at that step\n",
12719 total, nbMatches);
12720#endif
12721
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012722 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012723}
12724
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012725static int
12726xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12727 xmlXPathStepOpPtr op, xmlNodePtr * first);
12728
Daniel Veillardf06307e2001-07-03 10:35:50 +000012729/**
12730 * xmlXPathCompOpEvalFirst:
12731 * @ctxt: the XPath parser context with the compiled expression
12732 * @op: an XPath compiled operation
12733 * @first: the first elem found so far
12734 *
12735 * Evaluate the Precompiled XPath operation searching only the first
12736 * element in document order
12737 *
12738 * Returns the number of examined objects.
12739 */
12740static int
12741xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12742 xmlXPathStepOpPtr op, xmlNodePtr * first)
12743{
12744 int total = 0, cur;
12745 xmlXPathCompExprPtr comp;
12746 xmlXPathObjectPtr arg1, arg2;
12747
Daniel Veillard556c6682001-10-06 09:59:51 +000012748 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012749 comp = ctxt->comp;
12750 switch (op->op) {
12751 case XPATH_OP_END:
12752 return (0);
12753 case XPATH_OP_UNION:
12754 total =
12755 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12756 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012757 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012758 if ((ctxt->value != NULL)
12759 && (ctxt->value->type == XPATH_NODESET)
12760 && (ctxt->value->nodesetval != NULL)
12761 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12762 /*
12763 * limit tree traversing to first node in the result
12764 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012765 /*
12766 * OPTIMIZE TODO: This implicitely sorts
12767 * the result, even if not needed. E.g. if the argument
12768 * of the count() function, no sorting is needed.
12769 * OPTIMIZE TODO: How do we know if the node-list wasn't
12770 * aready sorted?
12771 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012772 if (ctxt->value->nodesetval->nodeNr > 1)
12773 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012774 *first = ctxt->value->nodesetval->nodeTab[0];
12775 }
12776 cur =
12777 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12778 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012779 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012780
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012781 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012782 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012783 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12784 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12785 xmlXPathReleaseObject(ctxt->context, arg1);
12786 xmlXPathReleaseObject(ctxt->context, arg2);
12787 XP_ERROR0(XPATH_INVALID_TYPE);
12788 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012789
12790 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12791 arg2->nodesetval);
12792 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012793 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012794 /* optimizer */
12795 if (total > cur)
12796 xmlXPathCompSwap(op);
12797 return (total + cur);
12798 case XPATH_OP_ROOT:
12799 xmlXPathRoot(ctxt);
12800 return (0);
12801 case XPATH_OP_NODE:
12802 if (op->ch1 != -1)
12803 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012804 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012805 if (op->ch2 != -1)
12806 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012807 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012808 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12809 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012810 return (total);
12811 case XPATH_OP_RESET:
12812 if (op->ch1 != -1)
12813 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012814 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012815 if (op->ch2 != -1)
12816 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012817 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012818 ctxt->context->node = NULL;
12819 return (total);
12820 case XPATH_OP_COLLECT:{
12821 if (op->ch1 == -1)
12822 return (total);
12823
12824 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012825 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012826
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012827 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012828 return (total);
12829 }
12830 case XPATH_OP_VALUE:
12831 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012832 xmlXPathCacheObjectCopy(ctxt->context,
12833 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012834 return (0);
12835 case XPATH_OP_SORT:
12836 if (op->ch1 != -1)
12837 total +=
12838 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12839 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012840 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012841 if ((ctxt->value != NULL)
12842 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012843 && (ctxt->value->nodesetval != NULL)
12844 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012845 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12846 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012847#ifdef XP_OPTIMIZED_FILTER_FIRST
12848 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012849 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012850 return (total);
12851#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012852 default:
12853 return (xmlXPathCompOpEval(ctxt, op));
12854 }
12855}
12856
12857/**
12858 * xmlXPathCompOpEvalLast:
12859 * @ctxt: the XPath parser context with the compiled expression
12860 * @op: an XPath compiled operation
12861 * @last: the last elem found so far
12862 *
12863 * Evaluate the Precompiled XPath operation searching only the last
12864 * element in document order
12865 *
William M. Brack08171912003-12-29 02:52:11 +000012866 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012867 */
12868static int
12869xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12870 xmlNodePtr * last)
12871{
12872 int total = 0, cur;
12873 xmlXPathCompExprPtr comp;
12874 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012875 xmlNodePtr bak;
12876 xmlDocPtr bakd;
12877 int pp;
12878 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012879
Daniel Veillard556c6682001-10-06 09:59:51 +000012880 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012881 comp = ctxt->comp;
12882 switch (op->op) {
12883 case XPATH_OP_END:
12884 return (0);
12885 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012886 bakd = ctxt->context->doc;
12887 bak = ctxt->context->node;
12888 pp = ctxt->context->proximityPosition;
12889 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012890 total =
12891 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012892 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012893 if ((ctxt->value != NULL)
12894 && (ctxt->value->type == XPATH_NODESET)
12895 && (ctxt->value->nodesetval != NULL)
12896 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12897 /*
12898 * limit tree traversing to first node in the result
12899 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012900 if (ctxt->value->nodesetval->nodeNr > 1)
12901 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012902 *last =
12903 ctxt->value->nodesetval->nodeTab[ctxt->value->
12904 nodesetval->nodeNr -
12905 1];
12906 }
William M. Brackce4fc562004-01-22 02:47:18 +000012907 ctxt->context->doc = bakd;
12908 ctxt->context->node = bak;
12909 ctxt->context->proximityPosition = pp;
12910 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012911 cur =
12912 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012913 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012914 if ((ctxt->value != NULL)
12915 && (ctxt->value->type == XPATH_NODESET)
12916 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012917 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012918 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012919
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012920 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012921 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012922 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12923 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12924 xmlXPathReleaseObject(ctxt->context, arg1);
12925 xmlXPathReleaseObject(ctxt->context, arg2);
12926 XP_ERROR0(XPATH_INVALID_TYPE);
12927 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012928
12929 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12930 arg2->nodesetval);
12931 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012932 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012933 /* optimizer */
12934 if (total > cur)
12935 xmlXPathCompSwap(op);
12936 return (total + cur);
12937 case XPATH_OP_ROOT:
12938 xmlXPathRoot(ctxt);
12939 return (0);
12940 case XPATH_OP_NODE:
12941 if (op->ch1 != -1)
12942 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012943 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012944 if (op->ch2 != -1)
12945 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012946 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012947 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12948 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012949 return (total);
12950 case XPATH_OP_RESET:
12951 if (op->ch1 != -1)
12952 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012953 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012954 if (op->ch2 != -1)
12955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012956 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012957 ctxt->context->node = NULL;
12958 return (total);
12959 case XPATH_OP_COLLECT:{
12960 if (op->ch1 == -1)
12961 return (0);
12962
12963 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012964 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012965
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012966 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012967 return (total);
12968 }
12969 case XPATH_OP_VALUE:
12970 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012971 xmlXPathCacheObjectCopy(ctxt->context,
12972 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012973 return (0);
12974 case XPATH_OP_SORT:
12975 if (op->ch1 != -1)
12976 total +=
12977 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12978 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012979 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012980 if ((ctxt->value != NULL)
12981 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012982 && (ctxt->value->nodesetval != NULL)
12983 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012984 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12985 return (total);
12986 default:
12987 return (xmlXPathCompOpEval(ctxt, op));
12988 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012989}
12990
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012991#ifdef XP_OPTIMIZED_FILTER_FIRST
12992static int
12993xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12994 xmlXPathStepOpPtr op, xmlNodePtr * first)
12995{
12996 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012997 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012998 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012999 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013000 xmlNodeSetPtr oldset;
13001 xmlNodePtr oldnode;
13002 xmlDocPtr oldDoc;
13003 int i;
13004
13005 CHECK_ERROR0;
13006 comp = ctxt->comp;
13007 /*
13008 * Optimization for ()[last()] selection i.e. the last elem
13009 */
13010 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13011 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13012 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13013 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013014
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013015 if ((f != -1) &&
13016 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13017 (comp->steps[f].value5 == NULL) &&
13018 (comp->steps[f].value == 0) &&
13019 (comp->steps[f].value4 != NULL) &&
13020 (xmlStrEqual
13021 (comp->steps[f].value4, BAD_CAST "last"))) {
13022 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013023
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013024 total +=
13025 xmlXPathCompOpEvalLast(ctxt,
13026 &comp->steps[op->ch1],
13027 &last);
13028 CHECK_ERROR0;
13029 /*
13030 * The nodeset should be in document order,
13031 * Keep only the last value
13032 */
13033 if ((ctxt->value != NULL) &&
13034 (ctxt->value->type == XPATH_NODESET) &&
13035 (ctxt->value->nodesetval != NULL) &&
13036 (ctxt->value->nodesetval->nodeTab != NULL) &&
13037 (ctxt->value->nodesetval->nodeNr > 1)) {
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013038 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013039 *first = *(ctxt->value->nodesetval->nodeTab);
13040 }
13041 return (total);
13042 }
13043 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013044
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013045 if (op->ch1 != -1)
13046 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13047 CHECK_ERROR0;
13048 if (op->ch2 == -1)
13049 return (total);
13050 if (ctxt->value == NULL)
13051 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013052
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013053#ifdef LIBXML_XPTR_ENABLED
13054 oldnode = ctxt->context->node;
13055 /*
13056 * Hum are we filtering the result of an XPointer expression
13057 */
13058 if (ctxt->value->type == XPATH_LOCATIONSET) {
13059 xmlXPathObjectPtr tmp = NULL;
13060 xmlLocationSetPtr newlocset = NULL;
13061 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013062
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013063 /*
13064 * Extract the old locset, and then evaluate the result of the
13065 * expression for all the element in the locset. use it to grow
13066 * up a new locset.
13067 */
13068 CHECK_TYPE0(XPATH_LOCATIONSET);
13069 obj = valuePop(ctxt);
13070 oldlocset = obj->user;
13071 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013072
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013073 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13074 ctxt->context->contextSize = 0;
13075 ctxt->context->proximityPosition = 0;
13076 if (op->ch2 != -1)
13077 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13078 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013079 if (res != NULL) {
13080 xmlXPathReleaseObject(ctxt->context, res);
13081 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013082 valuePush(ctxt, obj);
13083 CHECK_ERROR0;
13084 return (total);
13085 }
13086 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013087
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013088 for (i = 0; i < oldlocset->locNr; i++) {
13089 /*
13090 * Run the evaluation with a node list made of a
13091 * single item in the nodelocset.
13092 */
13093 ctxt->context->node = oldlocset->locTab[i]->user;
13094 ctxt->context->contextSize = oldlocset->locNr;
13095 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013096 if (tmp == NULL) {
13097 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13098 ctxt->context->node);
13099 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013100 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13101 ctxt->context->node) < 0) {
13102 ctxt->error = XPATH_MEMORY_ERROR;
13103 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013104 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013105 valuePush(ctxt, tmp);
13106 if (op->ch2 != -1)
13107 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13108 if (ctxt->error != XPATH_EXPRESSION_OK) {
13109 xmlXPathFreeObject(obj);
13110 return(0);
13111 }
13112 /*
13113 * The result of the evaluation need to be tested to
13114 * decided whether the filter succeeded or not
13115 */
13116 res = valuePop(ctxt);
13117 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13118 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013119 xmlXPathCacheObjectCopy(ctxt->context,
13120 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013121 }
13122 /*
13123 * Cleanup
13124 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013125 if (res != NULL) {
13126 xmlXPathReleaseObject(ctxt->context, res);
13127 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013128 if (ctxt->value == tmp) {
13129 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013130 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013131 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013132 * REVISIT TODO: Don't create a temporary nodeset
13133 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013134 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013135 /* OLD: xmlXPathFreeObject(res); */
13136 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013137 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013138 ctxt->context->node = NULL;
13139 /*
13140 * Only put the first node in the result, then leave.
13141 */
13142 if (newlocset->locNr > 0) {
13143 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13144 break;
13145 }
13146 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013147 if (tmp != NULL) {
13148 xmlXPathReleaseObject(ctxt->context, tmp);
13149 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013150 /*
13151 * The result is used as the new evaluation locset.
13152 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013153 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013154 ctxt->context->node = NULL;
13155 ctxt->context->contextSize = -1;
13156 ctxt->context->proximityPosition = -1;
13157 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13158 ctxt->context->node = oldnode;
13159 return (total);
13160 }
13161#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013162
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013163 /*
13164 * Extract the old set, and then evaluate the result of the
13165 * expression for all the element in the set. use it to grow
13166 * up a new set.
13167 */
13168 CHECK_TYPE0(XPATH_NODESET);
13169 obj = valuePop(ctxt);
13170 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013171
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013172 oldnode = ctxt->context->node;
13173 oldDoc = ctxt->context->doc;
13174 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013175
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013176 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13177 ctxt->context->contextSize = 0;
13178 ctxt->context->proximityPosition = 0;
13179 /* QUESTION TODO: Why was this code commented out?
13180 if (op->ch2 != -1)
13181 total +=
13182 xmlXPathCompOpEval(ctxt,
13183 &comp->steps[op->ch2]);
13184 CHECK_ERROR0;
13185 res = valuePop(ctxt);
13186 if (res != NULL)
13187 xmlXPathFreeObject(res);
13188 */
13189 valuePush(ctxt, obj);
13190 ctxt->context->node = oldnode;
13191 CHECK_ERROR0;
13192 } else {
13193 xmlNodeSetPtr newset;
13194 xmlXPathObjectPtr tmp = NULL;
13195 /*
13196 * Initialize the new set.
13197 * Also set the xpath document in case things like
13198 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013199 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013200 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013201 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013202
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013203 for (i = 0; i < oldset->nodeNr; i++) {
13204 /*
13205 * Run the evaluation with a node list made of
13206 * a single item in the nodeset.
13207 */
13208 ctxt->context->node = oldset->nodeTab[i];
13209 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13210 (oldset->nodeTab[i]->doc != NULL))
13211 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013212 if (tmp == NULL) {
13213 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13214 ctxt->context->node);
13215 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013216 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13217 ctxt->context->node) < 0) {
13218 ctxt->error = XPATH_MEMORY_ERROR;
13219 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013220 }
13221 valuePush(ctxt, tmp);
13222 ctxt->context->contextSize = oldset->nodeNr;
13223 ctxt->context->proximityPosition = i + 1;
13224 if (op->ch2 != -1)
13225 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13226 if (ctxt->error != XPATH_EXPRESSION_OK) {
13227 xmlXPathFreeNodeSet(newset);
13228 xmlXPathFreeObject(obj);
13229 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013230 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013231 /*
13232 * The result of the evaluation needs to be tested to
13233 * decide whether the filter succeeded or not
13234 */
13235 res = valuePop(ctxt);
13236 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013237 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13238 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013239 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013240 /*
13241 * Cleanup
13242 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013243 if (res != NULL) {
13244 xmlXPathReleaseObject(ctxt->context, res);
13245 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013246 if (ctxt->value == tmp) {
13247 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013248 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013249 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013250 * in order to avoid massive recreation inside this
13251 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013252 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013253 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013254 } else
13255 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013256 ctxt->context->node = NULL;
13257 /*
13258 * Only put the first node in the result, then leave.
13259 */
13260 if (newset->nodeNr > 0) {
13261 *first = *(newset->nodeTab);
13262 break;
13263 }
13264 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013265 if (tmp != NULL) {
13266 xmlXPathReleaseObject(ctxt->context, tmp);
13267 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013268 /*
13269 * The result is used as the new evaluation set.
13270 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013271 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013272 ctxt->context->node = NULL;
13273 ctxt->context->contextSize = -1;
13274 ctxt->context->proximityPosition = -1;
13275 /* may want to move this past the '}' later */
13276 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013277 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013278 }
13279 ctxt->context->node = oldnode;
13280 return(total);
13281}
13282#endif /* XP_OPTIMIZED_FILTER_FIRST */
13283
Owen Taylor3473f882001-02-23 17:55:21 +000013284/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013285 * xmlXPathCompOpEval:
13286 * @ctxt: the XPath parser context with the compiled expression
13287 * @op: an XPath compiled operation
13288 *
13289 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013290 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013291 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013292static int
13293xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13294{
13295 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013296 int equal, ret;
13297 xmlXPathCompExprPtr comp;
13298 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013299 xmlNodePtr bak;
13300 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013301 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013302 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013303
Daniel Veillard556c6682001-10-06 09:59:51 +000013304 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013305 comp = ctxt->comp;
13306 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013307 case XPATH_OP_END:
13308 return (0);
13309 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013310 bakd = ctxt->context->doc;
13311 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013312 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013313 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013314 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013315 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013316 xmlXPathBooleanFunction(ctxt, 1);
13317 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13318 return (total);
13319 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013320 ctxt->context->doc = bakd;
13321 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013322 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013323 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013324 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013325 if (ctxt->error) {
13326 xmlXPathFreeObject(arg2);
13327 return(0);
13328 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013329 xmlXPathBooleanFunction(ctxt, 1);
13330 arg1 = valuePop(ctxt);
13331 arg1->boolval &= arg2->boolval;
13332 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013333 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013334 return (total);
13335 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013336 bakd = ctxt->context->doc;
13337 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013338 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013339 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013340 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013341 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013342 xmlXPathBooleanFunction(ctxt, 1);
13343 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13344 return (total);
13345 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013346 ctxt->context->doc = bakd;
13347 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013348 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013349 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013350 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013351 if (ctxt->error) {
13352 xmlXPathFreeObject(arg2);
13353 return(0);
13354 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013355 xmlXPathBooleanFunction(ctxt, 1);
13356 arg1 = valuePop(ctxt);
13357 arg1->boolval |= arg2->boolval;
13358 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013359 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013360 return (total);
13361 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013362 bakd = ctxt->context->doc;
13363 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013364 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013365 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013366 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013367 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013368 ctxt->context->doc = bakd;
13369 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013370 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013371 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013372 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013373 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013374 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013375 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013376 else
13377 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013378 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013379 return (total);
13380 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013381 bakd = ctxt->context->doc;
13382 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013383 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013384 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013385 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013386 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013387 ctxt->context->doc = bakd;
13388 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013389 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013390 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013391 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013392 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013393 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013394 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013395 return (total);
13396 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013397 bakd = ctxt->context->doc;
13398 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013399 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013400 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013401 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013402 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013403 if (op->ch2 != -1) {
13404 ctxt->context->doc = bakd;
13405 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013406 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013407 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013408 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013409 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013410 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013411 if (op->value == 0)
13412 xmlXPathSubValues(ctxt);
13413 else if (op->value == 1)
13414 xmlXPathAddValues(ctxt);
13415 else if (op->value == 2)
13416 xmlXPathValueFlipSign(ctxt);
13417 else if (op->value == 3) {
13418 CAST_TO_NUMBER;
13419 CHECK_TYPE0(XPATH_NUMBER);
13420 }
13421 return (total);
13422 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013423 bakd = ctxt->context->doc;
13424 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013425 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013426 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013427 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013428 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013429 ctxt->context->doc = bakd;
13430 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013431 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013432 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013433 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013434 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013435 if (op->value == 0)
13436 xmlXPathMultValues(ctxt);
13437 else if (op->value == 1)
13438 xmlXPathDivValues(ctxt);
13439 else if (op->value == 2)
13440 xmlXPathModValues(ctxt);
13441 return (total);
13442 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013443 bakd = ctxt->context->doc;
13444 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013445 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013446 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013447 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013448 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013449 ctxt->context->doc = bakd;
13450 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013451 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013452 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013453 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013454 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013455
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013456 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013457 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013458 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13459 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13460 xmlXPathReleaseObject(ctxt->context, arg1);
13461 xmlXPathReleaseObject(ctxt->context, arg2);
13462 XP_ERROR0(XPATH_INVALID_TYPE);
13463 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013464
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013465 if ((arg1->nodesetval == NULL) ||
13466 ((arg2->nodesetval != NULL) &&
13467 (arg2->nodesetval->nodeNr != 0)))
13468 {
13469 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13470 arg2->nodesetval);
13471 }
13472
Daniel Veillardf06307e2001-07-03 10:35:50 +000013473 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013474 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013475 return (total);
13476 case XPATH_OP_ROOT:
13477 xmlXPathRoot(ctxt);
13478 return (total);
13479 case XPATH_OP_NODE:
13480 if (op->ch1 != -1)
13481 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013482 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013483 if (op->ch2 != -1)
13484 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013485 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013486 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13487 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013488 return (total);
13489 case XPATH_OP_RESET:
13490 if (op->ch1 != -1)
13491 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013492 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013493 if (op->ch2 != -1)
13494 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013495 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013496 ctxt->context->node = NULL;
13497 return (total);
13498 case XPATH_OP_COLLECT:{
13499 if (op->ch1 == -1)
13500 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013501
Daniel Veillardf06307e2001-07-03 10:35:50 +000013502 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013503 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013504
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013505 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013506 return (total);
13507 }
13508 case XPATH_OP_VALUE:
13509 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013510 xmlXPathCacheObjectCopy(ctxt->context,
13511 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013512 return (total);
13513 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013514 xmlXPathObjectPtr val;
13515
Daniel Veillardf06307e2001-07-03 10:35:50 +000013516 if (op->ch1 != -1)
13517 total +=
13518 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013519 if (op->value5 == NULL) {
13520 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13521 if (val == NULL) {
13522 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13523 return(0);
13524 }
13525 valuePush(ctxt, val);
13526 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013527 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013528
Daniel Veillardf06307e2001-07-03 10:35:50 +000013529 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13530 if (URI == NULL) {
13531 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013532 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13533 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013534 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013535 return (total);
13536 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013537 val = xmlXPathVariableLookupNS(ctxt->context,
13538 op->value4, URI);
13539 if (val == NULL) {
13540 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13541 return(0);
13542 }
13543 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013544 }
13545 return (total);
13546 }
13547 case XPATH_OP_FUNCTION:{
13548 xmlXPathFunction func;
13549 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013550 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013551 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013552
Daniel Veillardf5048b32011-08-18 17:10:13 +080013553 frame = xmlXPathSetFrame(ctxt);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013554 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013555 total +=
13556 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013557 if (ctxt->error != XPATH_EXPRESSION_OK) {
13558 xmlXPathPopFrame(ctxt, frame);
13559 return (total);
13560 }
13561 }
13562 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013563 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013564 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013565 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013566 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013567 return (total);
13568 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013569 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013570 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13571 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013572 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013573 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013574 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013575 return (total);
13576 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013577 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013578 if (op->cache != NULL)
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013579 func = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013580 else {
13581 const xmlChar *URI = NULL;
13582
13583 if (op->value5 == NULL)
13584 func =
13585 xmlXPathFunctionLookup(ctxt->context,
13586 op->value4);
13587 else {
13588 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13589 if (URI == NULL) {
13590 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013591 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13592 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013593 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013594 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013595 return (total);
13596 }
13597 func = xmlXPathFunctionLookupNS(ctxt->context,
13598 op->value4, URI);
13599 }
13600 if (func == NULL) {
13601 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013602 "xmlXPathCompOpEval: function %s not found\n",
13603 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013604 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013605 }
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013606 op->cache = func;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013607 op->cacheURI = (void *) URI;
13608 }
13609 oldFunc = ctxt->context->function;
13610 oldFuncURI = ctxt->context->functionURI;
13611 ctxt->context->function = op->value4;
13612 ctxt->context->functionURI = op->cacheURI;
13613 func(ctxt, op->value);
13614 ctxt->context->function = oldFunc;
13615 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013616 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013617 return (total);
13618 }
13619 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013620 bakd = ctxt->context->doc;
13621 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013622 pp = ctxt->context->proximityPosition;
13623 cs = ctxt->context->contextSize;
Nick Wellnhofer07def302014-03-21 19:38:08 +010013624 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013625 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013626 ctxt->context->contextSize = cs;
13627 ctxt->context->proximityPosition = pp;
13628 ctxt->context->node = bak;
13629 ctxt->context->doc = bakd;
13630 CHECK_ERROR0;
13631 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013632 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013633 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013634 ctxt->context->contextSize = cs;
13635 ctxt->context->proximityPosition = pp;
13636 ctxt->context->node = bak;
13637 ctxt->context->doc = bakd;
William M. Brack72ee48d2003-12-30 08:30:19 +000013638 CHECK_ERROR0;
13639 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013640 return (total);
13641 case XPATH_OP_PREDICATE:
13642 case XPATH_OP_FILTER:{
13643 xmlXPathObjectPtr res;
13644 xmlXPathObjectPtr obj, tmp;
13645 xmlNodeSetPtr newset = NULL;
13646 xmlNodeSetPtr oldset;
13647 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013648 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013649 int i;
13650
13651 /*
13652 * Optimization for ()[1] selection i.e. the first elem
13653 */
13654 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013655#ifdef XP_OPTIMIZED_FILTER_FIRST
13656 /*
13657 * FILTER TODO: Can we assume that the inner processing
13658 * will result in an ordered list if we have an
13659 * XPATH_OP_FILTER?
13660 * What about an additional field or flag on
13661 * xmlXPathObject like @sorted ? This way we wouln'd need
13662 * to assume anything, so it would be more robust and
13663 * easier to optimize.
13664 */
13665 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13666 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13667#else
13668 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13669#endif
13670 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013671 xmlXPathObjectPtr val;
13672
13673 val = comp->steps[op->ch2].value4;
13674 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13675 (val->floatval == 1.0)) {
13676 xmlNodePtr first = NULL;
13677
13678 total +=
13679 xmlXPathCompOpEvalFirst(ctxt,
13680 &comp->steps[op->ch1],
13681 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013682 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013683 /*
13684 * The nodeset should be in document order,
13685 * Keep only the first value
13686 */
13687 if ((ctxt->value != NULL) &&
13688 (ctxt->value->type == XPATH_NODESET) &&
13689 (ctxt->value->nodesetval != NULL) &&
13690 (ctxt->value->nodesetval->nodeNr > 1))
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013691 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13692 1, 1);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013693 return (total);
13694 }
13695 }
13696 /*
13697 * Optimization for ()[last()] selection i.e. the last elem
13698 */
13699 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13700 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13701 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13702 int f = comp->steps[op->ch2].ch1;
13703
13704 if ((f != -1) &&
13705 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13706 (comp->steps[f].value5 == NULL) &&
13707 (comp->steps[f].value == 0) &&
13708 (comp->steps[f].value4 != NULL) &&
13709 (xmlStrEqual
13710 (comp->steps[f].value4, BAD_CAST "last"))) {
13711 xmlNodePtr last = NULL;
13712
13713 total +=
13714 xmlXPathCompOpEvalLast(ctxt,
13715 &comp->steps[op->ch1],
13716 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013717 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013718 /*
13719 * The nodeset should be in document order,
13720 * Keep only the last value
13721 */
13722 if ((ctxt->value != NULL) &&
13723 (ctxt->value->type == XPATH_NODESET) &&
13724 (ctxt->value->nodesetval != NULL) &&
13725 (ctxt->value->nodesetval->nodeTab != NULL) &&
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013726 (ctxt->value->nodesetval->nodeNr > 1))
13727 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013728 return (total);
13729 }
13730 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013731 /*
13732 * Process inner predicates first.
13733 * Example "index[parent::book][1]":
13734 * ...
13735 * PREDICATE <-- we are here "[1]"
13736 * PREDICATE <-- process "[parent::book]" first
13737 * SORT
13738 * COLLECT 'parent' 'name' 'node' book
13739 * NODE
13740 * ELEM Object is a number : 1
13741 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013742 if (op->ch1 != -1)
13743 total +=
13744 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013745 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013746 if (op->ch2 == -1)
13747 return (total);
13748 if (ctxt->value == NULL)
13749 return (total);
13750
13751 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013752
13753#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013754 /*
13755 * Hum are we filtering the result of an XPointer expression
13756 */
13757 if (ctxt->value->type == XPATH_LOCATIONSET) {
13758 xmlLocationSetPtr newlocset = NULL;
13759 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013760
Daniel Veillardf06307e2001-07-03 10:35:50 +000013761 /*
13762 * Extract the old locset, and then evaluate the result of the
13763 * expression for all the element in the locset. use it to grow
13764 * up a new locset.
13765 */
13766 CHECK_TYPE0(XPATH_LOCATIONSET);
13767 obj = valuePop(ctxt);
13768 oldlocset = obj->user;
13769 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013770
Daniel Veillardf06307e2001-07-03 10:35:50 +000013771 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13772 ctxt->context->contextSize = 0;
13773 ctxt->context->proximityPosition = 0;
13774 if (op->ch2 != -1)
13775 total +=
13776 xmlXPathCompOpEval(ctxt,
13777 &comp->steps[op->ch2]);
13778 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013779 if (res != NULL) {
13780 xmlXPathReleaseObject(ctxt->context, res);
13781 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013782 valuePush(ctxt, obj);
13783 CHECK_ERROR0;
13784 return (total);
13785 }
13786 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013787
Daniel Veillardf06307e2001-07-03 10:35:50 +000013788 for (i = 0; i < oldlocset->locNr; i++) {
13789 /*
13790 * Run the evaluation with a node list made of a
13791 * single item in the nodelocset.
13792 */
13793 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013794 ctxt->context->contextSize = oldlocset->locNr;
13795 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013796 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13797 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013798 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013799
Daniel Veillardf06307e2001-07-03 10:35:50 +000013800 if (op->ch2 != -1)
13801 total +=
13802 xmlXPathCompOpEval(ctxt,
13803 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013804 if (ctxt->error != XPATH_EXPRESSION_OK) {
13805 xmlXPathFreeObject(obj);
13806 return(0);
13807 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013808
Daniel Veillardf06307e2001-07-03 10:35:50 +000013809 /*
13810 * The result of the evaluation need to be tested to
13811 * decided whether the filter succeeded or not
13812 */
13813 res = valuePop(ctxt);
13814 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13815 xmlXPtrLocationSetAdd(newlocset,
13816 xmlXPathObjectCopy
13817 (oldlocset->locTab[i]));
13818 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013819
Daniel Veillardf06307e2001-07-03 10:35:50 +000013820 /*
13821 * Cleanup
13822 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013823 if (res != NULL) {
13824 xmlXPathReleaseObject(ctxt->context, res);
13825 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013826 if (ctxt->value == tmp) {
13827 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013828 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013829 }
13830
13831 ctxt->context->node = NULL;
13832 }
13833
13834 /*
13835 * The result is used as the new evaluation locset.
13836 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013837 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013838 ctxt->context->node = NULL;
13839 ctxt->context->contextSize = -1;
13840 ctxt->context->proximityPosition = -1;
13841 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13842 ctxt->context->node = oldnode;
13843 return (total);
13844 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013845#endif /* LIBXML_XPTR_ENABLED */
13846
Daniel Veillardf06307e2001-07-03 10:35:50 +000013847 /*
13848 * Extract the old set, and then evaluate the result of the
13849 * expression for all the element in the set. use it to grow
13850 * up a new set.
13851 */
13852 CHECK_TYPE0(XPATH_NODESET);
13853 obj = valuePop(ctxt);
13854 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013855
Daniel Veillardf06307e2001-07-03 10:35:50 +000013856 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013857 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013858 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013859
Daniel Veillardf06307e2001-07-03 10:35:50 +000013860 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13861 ctxt->context->contextSize = 0;
13862 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013863/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013864 if (op->ch2 != -1)
13865 total +=
13866 xmlXPathCompOpEval(ctxt,
13867 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013868 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013869 res = valuePop(ctxt);
13870 if (res != NULL)
13871 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013872*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013873 valuePush(ctxt, obj);
13874 ctxt->context->node = oldnode;
13875 CHECK_ERROR0;
13876 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013877 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013878 /*
13879 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013880 * Also set the xpath document in case things like
13881 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013882 */
13883 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013884 /*
13885 * SPEC XPath 1.0:
13886 * "For each node in the node-set to be filtered, the
13887 * PredicateExpr is evaluated with that node as the
13888 * context node, with the number of nodes in the
13889 * node-set as the context size, and with the proximity
13890 * position of the node in the node-set with respect to
13891 * the axis as the context position;"
13892 * @oldset is the node-set" to be filtered.
13893 *
13894 * SPEC XPath 1.0:
13895 * "only predicates change the context position and
13896 * context size (see [2.4 Predicates])."
13897 * Example:
13898 * node-set context pos
13899 * nA 1
13900 * nB 2
13901 * nC 3
13902 * After applying predicate [position() > 1] :
13903 * node-set context pos
13904 * nB 1
13905 * nC 2
13906 *
13907 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013908 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013909 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013910 for (i = 0; i < oldset->nodeNr; i++) {
13911 /*
13912 * Run the evaluation with a node list made of
13913 * a single item in the nodeset.
13914 */
13915 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013916 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13917 (oldset->nodeTab[i]->doc != NULL))
13918 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013919 if (tmp == NULL) {
13920 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13921 ctxt->context->node);
13922 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013923 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13924 ctxt->context->node) < 0) {
13925 ctxt->error = XPATH_MEMORY_ERROR;
13926 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013927 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013928 valuePush(ctxt, tmp);
13929 ctxt->context->contextSize = oldset->nodeNr;
13930 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013931 /*
13932 * Evaluate the predicate against the context node.
13933 * Can/should we optimize position() predicates
13934 * here (e.g. "[1]")?
13935 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013936 if (op->ch2 != -1)
13937 total +=
13938 xmlXPathCompOpEval(ctxt,
13939 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013940 if (ctxt->error != XPATH_EXPRESSION_OK) {
13941 xmlXPathFreeNodeSet(newset);
13942 xmlXPathFreeObject(obj);
13943 return(0);
13944 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013945
Daniel Veillardf06307e2001-07-03 10:35:50 +000013946 /*
William M. Brack08171912003-12-29 02:52:11 +000013947 * The result of the evaluation needs to be tested to
13948 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013949 */
13950 /*
13951 * OPTIMIZE TODO: Can we use
13952 * xmlXPathNodeSetAdd*Unique()* instead?
13953 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013954 res = valuePop(ctxt);
13955 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013956 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13957 < 0)
13958 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013959 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013960
Daniel Veillardf06307e2001-07-03 10:35:50 +000013961 /*
13962 * Cleanup
13963 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013964 if (res != NULL) {
13965 xmlXPathReleaseObject(ctxt->context, res);
13966 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013967 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013968 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013969 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013970 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013971 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013972 * in order to avoid massive recreation inside this
13973 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013974 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013975 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013976 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013977 ctxt->context->node = NULL;
13978 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013979 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013980 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013981 /*
13982 * The result is used as the new evaluation set.
13983 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013984 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013985 ctxt->context->node = NULL;
13986 ctxt->context->contextSize = -1;
13987 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013988 /* may want to move this past the '}' later */
13989 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013990 valuePush(ctxt,
13991 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013992 }
13993 ctxt->context->node = oldnode;
13994 return (total);
13995 }
13996 case XPATH_OP_SORT:
13997 if (op->ch1 != -1)
13998 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013999 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014000 if ((ctxt->value != NULL) &&
14001 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000014002 (ctxt->value->nodesetval != NULL) &&
14003 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014004 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014005 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014006 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014007 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014008#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000014009 case XPATH_OP_RANGETO:{
14010 xmlXPathObjectPtr range;
14011 xmlXPathObjectPtr res, obj;
14012 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000014013 xmlLocationSetPtr newlocset = NULL;
14014 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014015 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000014016 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014017
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020014018 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014019 total +=
14020 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020014021 CHECK_ERROR0;
14022 }
14023 if (ctxt->value == NULL) {
14024 XP_ERROR0(XPATH_INVALID_OPERAND);
14025 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014026 if (op->ch2 == -1)
14027 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014028
William M. Brack08171912003-12-29 02:52:11 +000014029 if (ctxt->value->type == XPATH_LOCATIONSET) {
14030 /*
14031 * Extract the old locset, and then evaluate the result of the
14032 * expression for all the element in the locset. use it to grow
14033 * up a new locset.
14034 */
14035 CHECK_TYPE0(XPATH_LOCATIONSET);
14036 obj = valuePop(ctxt);
14037 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014038
William M. Brack08171912003-12-29 02:52:11 +000014039 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000014040 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000014041 ctxt->context->contextSize = 0;
14042 ctxt->context->proximityPosition = 0;
14043 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14044 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014045 if (res != NULL) {
14046 xmlXPathReleaseObject(ctxt->context, res);
14047 }
William M. Brack08171912003-12-29 02:52:11 +000014048 valuePush(ctxt, obj);
14049 CHECK_ERROR0;
14050 return (total);
14051 }
14052 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014053
William M. Brack08171912003-12-29 02:52:11 +000014054 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014055 /*
William M. Brack08171912003-12-29 02:52:11 +000014056 * Run the evaluation with a node list made of a
14057 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000014058 */
William M. Brackf7eb7942003-12-31 07:59:17 +000014059 ctxt->context->node = oldlocset->locTab[i]->user;
14060 ctxt->context->contextSize = oldlocset->locNr;
14061 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014062 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14063 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014064 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014065
Daniel Veillardf06307e2001-07-03 10:35:50 +000014066 if (op->ch2 != -1)
14067 total +=
14068 xmlXPathCompOpEval(ctxt,
14069 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014070 if (ctxt->error != XPATH_EXPRESSION_OK) {
14071 xmlXPathFreeObject(obj);
14072 return(0);
14073 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014074
Daniel Veillardf06307e2001-07-03 10:35:50 +000014075 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000014076 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014077 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000014078 (xmlLocationSetPtr)res->user;
14079 for (j=0; j<rloc->locNr; j++) {
14080 range = xmlXPtrNewRange(
14081 oldlocset->locTab[i]->user,
14082 oldlocset->locTab[i]->index,
14083 rloc->locTab[j]->user2,
14084 rloc->locTab[j]->index2);
14085 if (range != NULL) {
14086 xmlXPtrLocationSetAdd(newlocset, range);
14087 }
14088 }
14089 } else {
14090 range = xmlXPtrNewRangeNodeObject(
14091 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14092 if (range != NULL) {
14093 xmlXPtrLocationSetAdd(newlocset,range);
14094 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014095 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014096
Daniel Veillardf06307e2001-07-03 10:35:50 +000014097 /*
14098 * Cleanup
14099 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014100 if (res != NULL) {
14101 xmlXPathReleaseObject(ctxt->context, res);
14102 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014103 if (ctxt->value == tmp) {
14104 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014105 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014106 }
14107
14108 ctxt->context->node = NULL;
14109 }
William M. Brack72ee48d2003-12-30 08:30:19 +000014110 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000014111 CHECK_TYPE0(XPATH_NODESET);
14112 obj = valuePop(ctxt);
14113 oldset = obj->nodesetval;
14114 ctxt->context->node = NULL;
14115
14116 newlocset = xmlXPtrLocationSetCreate(NULL);
14117
14118 if (oldset != NULL) {
14119 for (i = 0; i < oldset->nodeNr; i++) {
14120 /*
14121 * Run the evaluation with a node list made of a single item
14122 * in the nodeset.
14123 */
14124 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014125 /*
14126 * OPTIMIZE TODO: Avoid recreation for every iteration.
14127 */
14128 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14129 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000014130 valuePush(ctxt, tmp);
14131
14132 if (op->ch2 != -1)
14133 total +=
14134 xmlXPathCompOpEval(ctxt,
14135 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014136 if (ctxt->error != XPATH_EXPRESSION_OK) {
14137 xmlXPathFreeObject(obj);
14138 return(0);
14139 }
William M. Brack08171912003-12-29 02:52:11 +000014140
William M. Brack08171912003-12-29 02:52:11 +000014141 res = valuePop(ctxt);
14142 range =
14143 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14144 res);
14145 if (range != NULL) {
14146 xmlXPtrLocationSetAdd(newlocset, range);
14147 }
14148
14149 /*
14150 * Cleanup
14151 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014152 if (res != NULL) {
14153 xmlXPathReleaseObject(ctxt->context, res);
14154 }
William M. Brack08171912003-12-29 02:52:11 +000014155 if (ctxt->value == tmp) {
14156 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014157 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000014158 }
14159
14160 ctxt->context->node = NULL;
14161 }
14162 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014163 }
14164
14165 /*
14166 * The result is used as the new evaluation set.
14167 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014168 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014169 ctxt->context->node = NULL;
14170 ctxt->context->contextSize = -1;
14171 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000014172 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014173 return (total);
14174 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014175#endif /* LIBXML_XPTR_ENABLED */
14176 }
14177 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000014178 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080014179 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014180 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014181}
14182
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014183/**
14184 * xmlXPathCompOpEvalToBoolean:
14185 * @ctxt: the XPath parser context
14186 *
14187 * Evaluates if the expression evaluates to true.
14188 *
14189 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14190 */
14191static int
14192xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014193 xmlXPathStepOpPtr op,
14194 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014195{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014196 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014197
14198start:
14199 /* comp = ctxt->comp; */
14200 switch (op->op) {
14201 case XPATH_OP_END:
14202 return (0);
14203 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014204 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014205 if (isPredicate)
14206 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14207 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014208 case XPATH_OP_SORT:
14209 /*
14210 * We don't need sorting for boolean results. Skip this one.
14211 */
14212 if (op->ch1 != -1) {
14213 op = &ctxt->comp->steps[op->ch1];
14214 goto start;
14215 }
14216 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014217 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014218 if (op->ch1 == -1)
14219 return(0);
14220
14221 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14222 if (ctxt->error != XPATH_EXPRESSION_OK)
14223 return(-1);
14224
14225 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14226 if (ctxt->error != XPATH_EXPRESSION_OK)
14227 return(-1);
14228
14229 resObj = valuePop(ctxt);
14230 if (resObj == NULL)
14231 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014232 break;
14233 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014234 /*
14235 * Fallback to call xmlXPathCompOpEval().
14236 */
14237 xmlXPathCompOpEval(ctxt, op);
14238 if (ctxt->error != XPATH_EXPRESSION_OK)
14239 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014240
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014241 resObj = valuePop(ctxt);
14242 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014243 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014244 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014245 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014246
14247 if (resObj) {
14248 int res;
14249
14250 if (resObj->type == XPATH_BOOLEAN) {
14251 res = resObj->boolval;
14252 } else if (isPredicate) {
14253 /*
14254 * For predicates a result of type "number" is handled
14255 * differently:
14256 * SPEC XPath 1.0:
14257 * "If the result is a number, the result will be converted
14258 * to true if the number is equal to the context position
14259 * and will be converted to false otherwise;"
14260 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014261 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014262 } else {
14263 res = xmlXPathCastToBoolean(resObj);
14264 }
14265 xmlXPathReleaseObject(ctxt->context, resObj);
14266 return(res);
14267 }
14268
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014269 return(0);
14270}
14271
Daniel Veillard56de87e2005-02-16 00:22:29 +000014272#ifdef XPATH_STREAMING
14273/**
14274 * xmlXPathRunStreamEval:
14275 * @ctxt: the XPath parser context with the compiled expression
14276 *
14277 * Evaluate the Precompiled Streamable XPath expression in the given context.
14278 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014279static int
14280xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14281 xmlXPathObjectPtr *resultSeq, int toBool)
14282{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014283 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014284 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014285 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014286 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014287 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014288 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014289
14290 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014291
14292 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014293 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014294 max_depth = xmlPatternMaxDepth(comp);
14295 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014296 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014297 if (max_depth == -2)
14298 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014299 min_depth = xmlPatternMinDepth(comp);
14300 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014301 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014302 from_root = xmlPatternFromRoot(comp);
14303 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014304 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014305#if 0
14306 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14307#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014308
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014309 if (! toBool) {
14310 if (resultSeq == NULL)
14311 return(-1);
14312 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14313 if (*resultSeq == NULL)
14314 return(-1);
14315 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014316
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014317 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014318 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014319 */
14320 if (min_depth == 0) {
14321 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014322 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014323 if (toBool)
14324 return(1);
14325 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014326 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014327 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014328 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014329 if (toBool)
14330 return(1);
14331 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014332 }
14333 }
14334 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014335 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014336 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014337
Daniel Veillard56de87e2005-02-16 00:22:29 +000014338 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014339 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014340 } else if (ctxt->node != NULL) {
14341 switch (ctxt->node->type) {
14342 case XML_ELEMENT_NODE:
14343 case XML_DOCUMENT_NODE:
14344 case XML_DOCUMENT_FRAG_NODE:
14345 case XML_HTML_DOCUMENT_NODE:
14346#ifdef LIBXML_DOCB_ENABLED
14347 case XML_DOCB_DOCUMENT_NODE:
14348#endif
14349 cur = ctxt->node;
14350 break;
14351 case XML_ATTRIBUTE_NODE:
14352 case XML_TEXT_NODE:
14353 case XML_CDATA_SECTION_NODE:
14354 case XML_ENTITY_REF_NODE:
14355 case XML_ENTITY_NODE:
14356 case XML_PI_NODE:
14357 case XML_COMMENT_NODE:
14358 case XML_NOTATION_NODE:
14359 case XML_DTD_NODE:
14360 case XML_DOCUMENT_TYPE_NODE:
14361 case XML_ELEMENT_DECL:
14362 case XML_ATTRIBUTE_DECL:
14363 case XML_ENTITY_DECL:
14364 case XML_NAMESPACE_DECL:
14365 case XML_XINCLUDE_START:
14366 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014367 break;
14368 }
14369 limit = cur;
14370 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014371 if (cur == NULL) {
14372 return(0);
14373 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014374
14375 patstream = xmlPatternGetStreamCtxt(comp);
14376 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014377 /*
14378 * QUESTION TODO: Is this an error?
14379 */
14380 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014381 }
14382
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014383 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014384
Daniel Veillard56de87e2005-02-16 00:22:29 +000014385 if (from_root) {
14386 ret = xmlStreamPush(patstream, NULL, NULL);
14387 if (ret < 0) {
14388 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014389 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014390 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014391 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014392 }
14393 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014394 depth = 0;
14395 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014396next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014397 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014398 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014399
14400 switch (cur->type) {
14401 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014402 case XML_TEXT_NODE:
14403 case XML_CDATA_SECTION_NODE:
14404 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014405 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014406 if (cur->type == XML_ELEMENT_NODE) {
14407 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014408 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014409 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014410 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14411 else
14412 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014413
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014414 if (ret < 0) {
14415 /* NOP. */
14416 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014417 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014418 goto return_1;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014419 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14420 < 0) {
14421 ctxt->lastError.domain = XML_FROM_XPATH;
14422 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14423 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014424 }
14425 if ((cur->children == NULL) || (depth >= max_depth)) {
14426 ret = xmlStreamPop(patstream);
14427 while (cur->next != NULL) {
14428 cur = cur->next;
14429 if ((cur->type != XML_ENTITY_DECL) &&
14430 (cur->type != XML_DTD_NODE))
14431 goto next_node;
14432 }
14433 }
14434 default:
14435 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014436 }
14437
Daniel Veillard56de87e2005-02-16 00:22:29 +000014438scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080014439 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014440 if ((cur->children != NULL) && (depth < max_depth)) {
14441 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014442 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014443 */
14444 if (cur->children->type != XML_ENTITY_DECL) {
14445 cur = cur->children;
14446 depth++;
14447 /*
14448 * Skip DTDs
14449 */
14450 if (cur->type != XML_DTD_NODE)
14451 continue;
14452 }
14453 }
14454
14455 if (cur == limit)
14456 break;
14457
14458 while (cur->next != NULL) {
14459 cur = cur->next;
14460 if ((cur->type != XML_ENTITY_DECL) &&
14461 (cur->type != XML_DTD_NODE))
14462 goto next_node;
14463 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014464
Daniel Veillard56de87e2005-02-16 00:22:29 +000014465 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014466 cur = cur->parent;
14467 depth--;
14468 if ((cur == NULL) || (cur == limit))
14469 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014470 if (cur->type == XML_ELEMENT_NODE) {
14471 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014472 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014473 ((cur->type == XML_TEXT_NODE) ||
14474 (cur->type == XML_CDATA_SECTION_NODE) ||
14475 (cur->type == XML_COMMENT_NODE) ||
14476 (cur->type == XML_PI_NODE)))
14477 {
14478 ret = xmlStreamPop(patstream);
14479 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014480 if (cur->next != NULL) {
14481 cur = cur->next;
14482 break;
14483 }
14484 } while (cur != NULL);
14485
14486 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014487
Daniel Veillard56de87e2005-02-16 00:22:29 +000014488done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014489
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014490#if 0
14491 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014492 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014493#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014494
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014495 if (patstream)
14496 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014497 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014498
14499return_1:
14500 if (patstream)
14501 xmlFreeStreamCtxt(patstream);
14502 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014503}
14504#endif /* XPATH_STREAMING */
14505
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014506/**
14507 * xmlXPathRunEval:
14508 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014509 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014510 *
14511 * Evaluate the Precompiled XPath expression in the given context.
14512 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014513static int
14514xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14515{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014516 xmlXPathCompExprPtr comp;
14517
14518 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014519 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014520
14521 if (ctxt->valueTab == NULL) {
14522 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014523 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014524 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14525 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014526 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014527 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014528 }
14529 ctxt->valueNr = 0;
14530 ctxt->valueMax = 10;
14531 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014532 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014533 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014534#ifdef XPATH_STREAMING
14535 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014536 int res;
14537
14538 if (toBool) {
14539 /*
14540 * Evaluation to boolean result.
14541 */
14542 res = xmlXPathRunStreamEval(ctxt->context,
14543 ctxt->comp->stream, NULL, 1);
14544 if (res != -1)
14545 return(res);
14546 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014547 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014548
14549 /*
14550 * Evaluation to a sequence.
14551 */
14552 res = xmlXPathRunStreamEval(ctxt->context,
14553 ctxt->comp->stream, &resObj, 0);
14554
14555 if ((res != -1) && (resObj != NULL)) {
14556 valuePush(ctxt, resObj);
14557 return(0);
14558 }
14559 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014560 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014561 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014562 /*
14563 * QUESTION TODO: This falls back to normal XPath evaluation
14564 * if res == -1. Is this intended?
14565 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014566 }
14567#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014568 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014569 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014570 xmlGenericError(xmlGenericErrorContext,
14571 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014572 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014573 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014574 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014575 return(xmlXPathCompOpEvalToBoolean(ctxt,
14576 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014577 else
14578 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14579
14580 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014581}
14582
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014583/************************************************************************
14584 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014585 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014586 * *
14587 ************************************************************************/
14588
14589/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014590 * xmlXPathEvalPredicate:
14591 * @ctxt: the XPath context
14592 * @res: the Predicate Expression evaluation result
14593 *
14594 * Evaluate a predicate result for the current node.
14595 * A PredicateExpr is evaluated by evaluating the Expr and converting
14596 * the result to a boolean. If the result is a number, the result will
14597 * be converted to true if the number is equal to the position of the
14598 * context node in the context node list (as returned by the position
14599 * function) and will be converted to false otherwise; if the result
14600 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014601 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014602 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014603 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014604 */
14605int
14606xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014607 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014608 switch (res->type) {
14609 case XPATH_BOOLEAN:
14610 return(res->boolval);
14611 case XPATH_NUMBER:
14612 return(res->floatval == ctxt->proximityPosition);
14613 case XPATH_NODESET:
14614 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014615 if (res->nodesetval == NULL)
14616 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014617 return(res->nodesetval->nodeNr != 0);
14618 case XPATH_STRING:
14619 return((res->stringval != NULL) &&
14620 (xmlStrlen(res->stringval) != 0));
14621 default:
14622 STRANGE
14623 }
14624 return(0);
14625}
14626
14627/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014628 * xmlXPathEvaluatePredicateResult:
14629 * @ctxt: the XPath Parser context
14630 * @res: the Predicate Expression evaluation result
14631 *
14632 * Evaluate a predicate result for the current node.
14633 * A PredicateExpr is evaluated by evaluating the Expr and converting
14634 * the result to a boolean. If the result is a number, the result will
14635 * be converted to true if the number is equal to the position of the
14636 * context node in the context node list (as returned by the position
14637 * function) and will be converted to false otherwise; if the result
14638 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014639 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014640 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014641 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014642 */
14643int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014644xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014645 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014646 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014647 switch (res->type) {
14648 case XPATH_BOOLEAN:
14649 return(res->boolval);
14650 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014651#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014652 return((res->floatval == ctxt->context->proximityPosition) &&
14653 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014654#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014655 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014656#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014657 case XPATH_NODESET:
14658 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014659 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014660 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014661 return(res->nodesetval->nodeNr != 0);
14662 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014663 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014664#ifdef LIBXML_XPTR_ENABLED
14665 case XPATH_LOCATIONSET:{
14666 xmlLocationSetPtr ptr = res->user;
14667 if (ptr == NULL)
14668 return(0);
14669 return (ptr->locNr != 0);
14670 }
14671#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014672 default:
14673 STRANGE
14674 }
14675 return(0);
14676}
14677
Daniel Veillard56de87e2005-02-16 00:22:29 +000014678#ifdef XPATH_STREAMING
14679/**
14680 * xmlXPathTryStreamCompile:
14681 * @ctxt: an XPath context
14682 * @str: the XPath expression
14683 *
14684 * Try to compile the XPath expression as a streamable subset.
14685 *
14686 * Returns the compiled expression or NULL if failed to compile.
14687 */
14688static xmlXPathCompExprPtr
14689xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14690 /*
14691 * Optimization: use streaming patterns when the XPath expression can
14692 * be compiled to a stream lookup
14693 */
14694 xmlPatternPtr stream;
14695 xmlXPathCompExprPtr comp;
14696 xmlDictPtr dict = NULL;
14697 const xmlChar **namespaces = NULL;
14698 xmlNsPtr ns;
14699 int i, j;
14700
14701 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14702 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014703 const xmlChar *tmp;
14704
14705 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014706 * We don't try to handle expressions using the verbose axis
14707 * specifiers ("::"), just the simplied form at this point.
14708 * Additionally, if there is no list of namespaces available and
14709 * there's a ":" in the expression, indicating a prefixed QName,
14710 * then we won't try to compile either. xmlPatterncompile() needs
14711 * to have a list of namespaces at compilation time in order to
14712 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014713 */
14714 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014715 if ((tmp != NULL) &&
14716 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014717 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014718
Daniel Veillard56de87e2005-02-16 00:22:29 +000014719 if (ctxt != NULL) {
14720 dict = ctxt->dict;
14721 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014722 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014723 if (namespaces == NULL) {
14724 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14725 return(NULL);
14726 }
14727 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14728 ns = ctxt->namespaces[j];
14729 namespaces[i++] = ns->href;
14730 namespaces[i++] = ns->prefix;
14731 }
14732 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014733 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014734 }
14735 }
14736
William M. Brackea152c02005-06-09 18:12:28 +000014737 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14738 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014739 if (namespaces != NULL) {
14740 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014741 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014742 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14743 comp = xmlXPathNewCompExpr();
14744 if (comp == NULL) {
14745 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14746 return(NULL);
14747 }
14748 comp->stream = stream;
14749 comp->dict = dict;
14750 if (comp->dict)
14751 xmlDictReference(comp->dict);
14752 return(comp);
14753 }
14754 xmlFreePattern(stream);
14755 }
14756 return(NULL);
14757}
14758#endif /* XPATH_STREAMING */
14759
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014760static void
Nick Wellnhofer62270532012-08-19 19:42:38 +020014761xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014762{
14763 /*
14764 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14765 * internal representation.
14766 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014767
Nick Wellnhoferb4bcba22013-08-05 00:15:11 +020014768 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14769 (op->ch1 != -1) &&
14770 (op->ch2 == -1 /* no predicate */))
Nick Wellnhofer62270532012-08-19 19:42:38 +020014771 {
14772 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14773
14774 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14775 ((xmlXPathAxisVal) prevop->value ==
14776 AXIS_DESCENDANT_OR_SELF) &&
14777 (prevop->ch2 == -1) &&
14778 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14779 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14780 {
14781 /*
14782 * This is a "descendant-or-self::node()" without predicates.
14783 * Try to eliminate it.
14784 */
14785
14786 switch ((xmlXPathAxisVal) op->value) {
14787 case AXIS_CHILD:
14788 case AXIS_DESCENDANT:
14789 /*
14790 * Convert "descendant-or-self::node()/child::" or
14791 * "descendant-or-self::node()/descendant::" to
14792 * "descendant::"
14793 */
14794 op->ch1 = prevop->ch1;
14795 op->value = AXIS_DESCENDANT;
14796 break;
14797 case AXIS_SELF:
14798 case AXIS_DESCENDANT_OR_SELF:
14799 /*
14800 * Convert "descendant-or-self::node()/self::" or
14801 * "descendant-or-self::node()/descendant-or-self::" to
14802 * to "descendant-or-self::"
14803 */
14804 op->ch1 = prevop->ch1;
14805 op->value = AXIS_DESCENDANT_OR_SELF;
14806 break;
14807 default:
14808 break;
14809 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014810 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014811 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014812
Nick Wellnhofer839689a2016-04-27 18:00:12 +020014813 /* OP_VALUE has invalid ch1. */
14814 if (op->op == XPATH_OP_VALUE)
14815 return;
14816
Nick Wellnhofer62270532012-08-19 19:42:38 +020014817 /* Recurse */
14818 if (op->ch1 != -1)
14819 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014820 if (op->ch2 != -1)
Nick Wellnhofer62270532012-08-19 19:42:38 +020014821 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014822}
14823
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014824/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014825 * xmlXPathCtxtCompile:
14826 * @ctxt: an XPath context
14827 * @str: the XPath expression
14828 *
14829 * Compile an XPath expression
14830 *
14831 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14832 * the caller has to free the object.
14833 */
14834xmlXPathCompExprPtr
14835xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14836 xmlXPathParserContextPtr pctxt;
14837 xmlXPathCompExprPtr comp;
14838
Daniel Veillard56de87e2005-02-16 00:22:29 +000014839#ifdef XPATH_STREAMING
14840 comp = xmlXPathTryStreamCompile(ctxt, str);
14841 if (comp != NULL)
14842 return(comp);
14843#endif
14844
Daniel Veillard4773df22004-01-23 13:15:13 +000014845 xmlXPathInit();
14846
14847 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014848 if (pctxt == NULL)
14849 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014850 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014851
14852 if( pctxt->error != XPATH_EXPRESSION_OK )
14853 {
14854 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014855 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014856 }
14857
14858 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014859 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014860 * aleksey: in some cases this line prints *second* error message
14861 * (see bug #78858) and probably this should be fixed.
14862 * However, we are not sure that all error messages are printed
14863 * out in other places. It's not critical so we leave it as-is for now
14864 */
14865 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14866 comp = NULL;
14867 } else {
14868 comp = pctxt->comp;
14869 pctxt->comp = NULL;
14870 }
14871 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014872
Daniel Veillard4773df22004-01-23 13:15:13 +000014873 if (comp != NULL) {
14874 comp->expr = xmlStrdup(str);
14875#ifdef DEBUG_EVAL_COUNTS
14876 comp->string = xmlStrdup(str);
14877 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014878#endif
Nick Wellnhofer62270532012-08-19 19:42:38 +020014879 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14880 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014881 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014882 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014883 return(comp);
14884}
14885
14886/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014887 * xmlXPathCompile:
14888 * @str: the XPath expression
14889 *
14890 * Compile an XPath expression
14891 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014892 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014893 * the caller has to free the object.
14894 */
14895xmlXPathCompExprPtr
14896xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014897 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014898}
14899
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014900/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014901 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014902 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014903 * @ctxt: the XPath context
14904 * @resObj: the resulting XPath object or NULL
14905 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014906 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014907 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014908 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014909 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014910 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014911 * the caller has to free the object.
14912 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014913static int
14914xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14915 xmlXPathContextPtr ctxt,
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014916 xmlXPathObjectPtr *resObjPtr,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014917 int toBool)
14918{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014919 xmlXPathParserContextPtr pctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014920 xmlXPathObjectPtr resObj;
Daniel Veillard81463942001-10-16 12:34:39 +000014921#ifndef LIBXML_THREAD_ENABLED
14922 static int reentance = 0;
14923#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014924 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014925
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014926 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014927
14928 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014929 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014930 xmlXPathInit();
14931
Daniel Veillard81463942001-10-16 12:34:39 +000014932#ifndef LIBXML_THREAD_ENABLED
14933 reentance++;
14934 if (reentance > 1)
14935 xmlXPathDisableOptimizer = 1;
14936#endif
14937
Daniel Veillardf06307e2001-07-03 10:35:50 +000014938#ifdef DEBUG_EVAL_COUNTS
14939 comp->nb++;
14940 if ((comp->string != NULL) && (comp->nb > 100)) {
14941 fprintf(stderr, "100 x %s\n", comp->string);
14942 comp->nb = 0;
14943 }
14944#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014945 pctxt = xmlXPathCompParserContext(comp, ctxt);
14946 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014947
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014948 if (pctxt->error != XPATH_EXPRESSION_OK) {
14949 resObj = NULL;
14950 } else {
14951 resObj = valuePop(pctxt);
14952 if (resObj == NULL) {
Nick Wellnhofera07a4e92017-05-27 17:04:12 +020014953 if (!toBool)
14954 xmlGenericError(xmlGenericErrorContext,
14955 "xmlXPathCompiledEval: No result on the stack.\n");
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014956 } else if (pctxt->valueNr > 0) {
14957 xmlGenericError(xmlGenericErrorContext,
14958 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14959 pctxt->valueNr);
14960 }
Owen Taylor3473f882001-02-23 17:55:21 +000014961 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014962
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014963 if (resObjPtr)
14964 *resObjPtr = resObj;
14965 else
14966 xmlXPathReleaseObject(ctxt, resObj);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014967
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014968 pctxt->comp = NULL;
14969 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014970#ifndef LIBXML_THREAD_ENABLED
14971 reentance--;
14972#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014973
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014974 return(res);
14975}
14976
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014977/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014978 * xmlXPathCompiledEval:
14979 * @comp: the compiled XPath expression
14980 * @ctx: the XPath context
14981 *
14982 * Evaluate the Precompiled XPath expression in the given context.
14983 *
14984 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14985 * the caller has to free the object.
14986 */
14987xmlXPathObjectPtr
14988xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14989{
14990 xmlXPathObjectPtr res = NULL;
14991
14992 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14993 return(res);
14994}
14995
14996/**
14997 * xmlXPathCompiledEvalToBoolean:
14998 * @comp: the compiled XPath expression
14999 * @ctxt: the XPath context
15000 *
15001 * Applies the XPath boolean() function on the result of the given
15002 * compiled expression.
15003 *
15004 * Returns 1 if the expression evaluated to true, 0 if to false and
15005 * -1 in API and internal errors.
15006 */
15007int
15008xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
15009 xmlXPathContextPtr ctxt)
15010{
15011 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
15012}
15013
15014/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000015015 * xmlXPathEvalExpr:
15016 * @ctxt: the XPath Parser context
15017 *
15018 * Parse and evaluate an XPath expression in the given context,
15019 * then push the result on the context stack
15020 */
15021void
15022xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000015023#ifdef XPATH_STREAMING
15024 xmlXPathCompExprPtr comp;
15025#endif
15026
Daniel Veillarda82b1822004-11-08 16:24:57 +000015027 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015028
Daniel Veillard56de87e2005-02-16 00:22:29 +000015029#ifdef XPATH_STREAMING
15030 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15031 if (comp != NULL) {
15032 if (ctxt->comp != NULL)
15033 xmlXPathFreeCompExpr(ctxt->comp);
15034 ctxt->comp = comp;
Daniel Veillard56de87e2005-02-16 00:22:29 +000015035 } else
15036#endif
15037 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000015038 xmlXPathCompileExpr(ctxt, 1);
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020015039 CHECK_ERROR;
15040
15041 /* Check for trailing characters. */
15042 if (*ctxt->cur != 0)
15043 XP_ERROR(XPATH_EXPR_ERROR);
15044
15045 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
Nick Wellnhofer62270532012-08-19 19:42:38 +020015046 xmlXPathOptimizeExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000015047 &ctxt->comp->steps[ctxt->comp->last]);
Daniel Veillard56de87e2005-02-16 00:22:29 +000015048 }
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020015049
Daniel Veillard45490ae2008-07-29 09:13:19 +000015050 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000015051}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015052
15053/**
15054 * xmlXPathEval:
15055 * @str: the XPath expression
15056 * @ctx: the XPath context
15057 *
15058 * Evaluate the XPath Location Path in the given context.
15059 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000015060 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015061 * the caller has to free the object.
15062 */
15063xmlXPathObjectPtr
15064xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15065 xmlXPathParserContextPtr ctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020015066 xmlXPathObjectPtr res;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015067
William M. Brackf13f77f2004-11-12 16:03:48 +000015068 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015069
William M. Brackf13f77f2004-11-12 16:03:48 +000015070 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015071
15072 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000015073 if (ctxt == NULL)
15074 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015075 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015076
Nick Wellnhoferc8519702017-05-27 15:26:11 +020015077 if (ctxt->error != XPATH_EXPRESSION_OK) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015078 res = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015079 } else {
15080 res = valuePop(ctxt);
Nick Wellnhoferc8519702017-05-27 15:26:11 +020015081 if (res == NULL) {
15082 xmlGenericError(xmlGenericErrorContext,
15083 "xmlXPathCompiledEval: No result on the stack.\n");
15084 } else if (ctxt->valueNr > 0) {
15085 xmlGenericError(xmlGenericErrorContext,
15086 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
15087 ctxt->valueNr);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015088 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015089 }
15090
Owen Taylor3473f882001-02-23 17:55:21 +000015091 xmlXPathFreeParserContext(ctxt);
15092 return(res);
15093}
15094
15095/**
Alex Bligh28876af2013-03-23 17:23:27 +000015096 * xmlXPathSetContextNode:
15097 * @node: the node to to use as the context node
15098 * @ctx: the XPath context
15099 *
15100 * Sets 'node' as the context node. The node must be in the same
15101 * document as that associated with the context.
15102 *
15103 * Returns -1 in case of error or 0 if successful
15104 */
15105int
15106xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15107 if ((node == NULL) || (ctx == NULL))
15108 return(-1);
15109
15110 if (node->doc == ctx->doc) {
15111 ctx->node = node;
15112 return(0);
15113 }
15114 return(-1);
15115}
15116
15117/**
15118 * xmlXPathNodeEval:
15119 * @node: the node to to use as the context node
15120 * @str: the XPath expression
15121 * @ctx: the XPath context
15122 *
15123 * Evaluate the XPath Location Path in the given context. The node 'node'
15124 * is set as the context node. The context node is not restored.
15125 *
15126 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15127 * the caller has to free the object.
15128 */
15129xmlXPathObjectPtr
15130xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15131 if (str == NULL)
15132 return(NULL);
15133 if (xmlXPathSetContextNode(node, ctx) < 0)
15134 return(NULL);
15135 return(xmlXPathEval(str, ctx));
15136}
15137
15138/**
Owen Taylor3473f882001-02-23 17:55:21 +000015139 * xmlXPathEvalExpression:
15140 * @str: the XPath expression
15141 * @ctxt: the XPath context
15142 *
Nick Wellnhofer640a3682017-05-27 14:59:49 +020015143 * Alias for xmlXPathEval.
Owen Taylor3473f882001-02-23 17:55:21 +000015144 */
15145xmlXPathObjectPtr
15146xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Nick Wellnhofer640a3682017-05-27 14:59:49 +020015147 return(xmlXPathEval(str, ctxt));
Owen Taylor3473f882001-02-23 17:55:21 +000015148}
15149
Daniel Veillard42766c02002-08-22 20:52:17 +000015150/************************************************************************
15151 * *
15152 * Extra functions not pertaining to the XPath spec *
15153 * *
15154 ************************************************************************/
15155/**
15156 * xmlXPathEscapeUriFunction:
15157 * @ctxt: the XPath Parser context
15158 * @nargs: the number of arguments
15159 *
15160 * Implement the escape-uri() XPath function
15161 * string escape-uri(string $str, bool $escape-reserved)
15162 *
15163 * This function applies the URI escaping rules defined in section 2 of [RFC
15164 * 2396] to the string supplied as $uri-part, which typically represents all
15165 * or part of a URI. The effect of the function is to replace any special
15166 * character in the string by an escape sequence of the form %xx%yy...,
15167 * where xxyy... is the hexadecimal representation of the octets used to
15168 * represent the character in UTF-8.
15169 *
15170 * The set of characters that are escaped depends on the setting of the
15171 * boolean argument $escape-reserved.
15172 *
15173 * If $escape-reserved is true, all characters are escaped other than lower
15174 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15175 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15176 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15177 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15178 * A-F).
15179 *
15180 * If $escape-reserved is false, the behavior differs in that characters
15181 * referred to in [RFC 2396] as reserved characters are not escaped. These
15182 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015183 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015184 * [RFC 2396] does not define whether escaped URIs should use lower case or
15185 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15186 * compared using string comparison functions, this function must always use
15187 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015188 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015189 * Generally, $escape-reserved should be set to true when escaping a string
15190 * that is to form a single part of a URI, and to false when escaping an
15191 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015192 *
15193 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015194 * utf-8 and then converted according to RFC 2396.
15195 *
15196 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015197 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015198 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15199 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15200 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15201 *
15202 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015203static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015204xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15205 xmlXPathObjectPtr str;
15206 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080015207 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000015208 xmlChar *cptr;
15209 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015210
Daniel Veillard42766c02002-08-22 20:52:17 +000015211 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015212
Daniel Veillard42766c02002-08-22 20:52:17 +000015213 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015214
Daniel Veillard42766c02002-08-22 20:52:17 +000015215 CAST_TO_STRING;
15216 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015217
Daniel Veillardade10f22012-07-12 09:43:27 +080015218 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015219
Daniel Veillard42766c02002-08-22 20:52:17 +000015220 escape[0] = '%';
15221 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015222
Daniel Veillard42766c02002-08-22 20:52:17 +000015223 if (target) {
15224 for (cptr = str->stringval; *cptr; cptr++) {
15225 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15226 (*cptr >= 'a' && *cptr <= 'z') ||
15227 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015228 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015229 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15230 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015231 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015232 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15233 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15234 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15235 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15236 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15237 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15238 (!escape_reserved &&
15239 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15240 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15241 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15242 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080015243 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000015244 } else {
15245 if ((*cptr >> 4) < 10)
15246 escape[1] = '0' + (*cptr >> 4);
15247 else
15248 escape[1] = 'A' - 10 + (*cptr >> 4);
15249 if ((*cptr & 0xF) < 10)
15250 escape[2] = '0' + (*cptr & 0xF);
15251 else
15252 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015253
Daniel Veillardade10f22012-07-12 09:43:27 +080015254 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000015255 }
15256 }
15257 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015258 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080015259 xmlBufContent(target)));
15260 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015261 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015262}
15263
Owen Taylor3473f882001-02-23 17:55:21 +000015264/**
15265 * xmlXPathRegisterAllFunctions:
15266 * @ctxt: the XPath context
15267 *
15268 * Registers all default XPath functions in this context
15269 */
15270void
15271xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15272{
15273 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15274 xmlXPathBooleanFunction);
15275 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15276 xmlXPathCeilingFunction);
15277 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15278 xmlXPathCountFunction);
15279 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15280 xmlXPathConcatFunction);
15281 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15282 xmlXPathContainsFunction);
15283 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15284 xmlXPathIdFunction);
15285 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15286 xmlXPathFalseFunction);
15287 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15288 xmlXPathFloorFunction);
15289 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15290 xmlXPathLastFunction);
15291 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15292 xmlXPathLangFunction);
15293 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15294 xmlXPathLocalNameFunction);
15295 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15296 xmlXPathNotFunction);
15297 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15298 xmlXPathNameFunction);
15299 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15300 xmlXPathNamespaceURIFunction);
15301 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15302 xmlXPathNormalizeFunction);
15303 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15304 xmlXPathNumberFunction);
15305 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15306 xmlXPathPositionFunction);
15307 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15308 xmlXPathRoundFunction);
15309 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15310 xmlXPathStringFunction);
15311 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15312 xmlXPathStringLengthFunction);
15313 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15314 xmlXPathStartsWithFunction);
15315 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15316 xmlXPathSubstringFunction);
15317 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15318 xmlXPathSubstringBeforeFunction);
15319 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15320 xmlXPathSubstringAfterFunction);
15321 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15322 xmlXPathSumFunction);
15323 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15324 xmlXPathTrueFunction);
15325 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15326 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015327
15328 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15329 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15330 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015331}
15332
15333#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015334#define bottom_xpath
15335#include "elfgcchack.h"