blob: 318b5b4ab869c547ed9dd2731a2b9c422fcbaa37 [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");
Nick Wellnhofer7482f412017-06-01 22:00:19 +02003109 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3110 (number == (int) number)) {
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003111 char work[30];
3112 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00003113 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003114
3115 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003116 if (value == 0) {
3117 *ptr++ = '0';
3118 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00003119 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003120 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00003121 while ((*cur) && (ptr - buffer < buffersize)) {
3122 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003123 }
3124 }
3125 if (ptr - buffer < buffersize) {
3126 *ptr = 0;
3127 } else if (buffersize > 0) {
3128 ptr--;
3129 *ptr = 0;
3130 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003131 } else {
William M. Brackca797882007-05-11 14:45:53 +00003132 /*
3133 For the dimension of work,
3134 DBL_DIG is number of significant digits
3135 EXPONENT is only needed for "scientific notation"
3136 3 is sign, decimal point, and terminating zero
3137 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3138 Note that this dimension is slightly (a few characters)
3139 larger than actually necessary.
3140 */
3141 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003142 int integer_place, fraction_place;
3143 char *ptr;
3144 char *after_fraction;
3145 double absolute_value;
3146 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003147
Bjorn Reese70a9da52001-04-21 16:57:29 +00003148 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003149
Bjorn Reese70a9da52001-04-21 16:57:29 +00003150 /*
3151 * First choose format - scientific or regular floating point.
3152 * In either case, result is in work, and after_fraction points
3153 * just past the fractional part.
3154 */
3155 if ( ((absolute_value > UPPER_DOUBLE) ||
3156 (absolute_value < LOWER_DOUBLE)) &&
3157 (absolute_value != 0.0) ) {
3158 /* Use scientific notation */
3159 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3160 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003161 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00003162 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00003163 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003164
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003165 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003166 else {
3167 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00003168 if (absolute_value > 0.0) {
3169 integer_place = (int)log10(absolute_value);
3170 if (integer_place > 0)
3171 fraction_place = DBL_DIG - integer_place - 1;
3172 else
3173 fraction_place = DBL_DIG - integer_place;
3174 } else {
3175 fraction_place = 1;
3176 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003177 size = snprintf(work, sizeof(work), "%0.*f",
3178 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003179 }
3180
Daniel Veillardb9e4d5b2013-07-22 13:21:31 +08003181 /* Remove leading spaces sometimes inserted by snprintf */
3182 while (work[0] == ' ') {
3183 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3184 size--;
3185 }
3186
Bjorn Reese70a9da52001-04-21 16:57:29 +00003187 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00003188 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003189 ptr = after_fraction;
3190 while (*(--ptr) == '0')
3191 ;
3192 if (*ptr != '.')
3193 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003194 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003195
3196 /* Finally copy result back to caller */
3197 size = strlen(work) + 1;
3198 if (size > buffersize) {
3199 work[buffersize - 1] = 0;
3200 size = buffersize;
3201 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003202 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003203 }
3204 break;
3205 }
3206}
3207
Owen Taylor3473f882001-02-23 17:55:21 +00003208
3209/************************************************************************
3210 * *
3211 * Routines to handle NodeSets *
3212 * *
3213 ************************************************************************/
3214
3215/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003216 * xmlXPathOrderDocElems:
3217 * @doc: an input document
3218 *
3219 * Call this routine to speed up XPath computation on static documents.
3220 * This stamps all the element nodes with the document order
3221 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00003222 * field, the value stored is actually - the node number (starting at -1)
3223 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003224 *
William M. Brack08171912003-12-29 02:52:11 +00003225 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003226 * of error.
3227 */
3228long
3229xmlXPathOrderDocElems(xmlDocPtr doc) {
3230 long count = 0;
3231 xmlNodePtr cur;
3232
3233 if (doc == NULL)
3234 return(-1);
3235 cur = doc->children;
3236 while (cur != NULL) {
3237 if (cur->type == XML_ELEMENT_NODE) {
3238 cur->content = (void *) (-(++count));
3239 if (cur->children != NULL) {
3240 cur = cur->children;
3241 continue;
3242 }
3243 }
3244 if (cur->next != NULL) {
3245 cur = cur->next;
3246 continue;
3247 }
3248 do {
3249 cur = cur->parent;
3250 if (cur == NULL)
3251 break;
3252 if (cur == (xmlNodePtr) doc) {
3253 cur = NULL;
3254 break;
3255 }
3256 if (cur->next != NULL) {
3257 cur = cur->next;
3258 break;
3259 }
3260 } while (cur != NULL);
3261 }
3262 return(count);
3263}
3264
3265/**
Owen Taylor3473f882001-02-23 17:55:21 +00003266 * xmlXPathCmpNodes:
3267 * @node1: the first node
3268 * @node2: the second node
3269 *
3270 * Compare two nodes w.r.t document order
3271 *
3272 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00003273 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003274 */
3275int
3276xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3277 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003278 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003279 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003280 xmlNodePtr cur, root;
3281
3282 if ((node1 == NULL) || (node2 == NULL))
3283 return(-2);
3284 /*
3285 * a couple of optimizations which will avoid computations in most cases
3286 */
William M. Brackee0b9822007-03-07 08:15:01 +00003287 if (node1 == node2) /* trivial case */
3288 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00003289 if (node1->type == XML_ATTRIBUTE_NODE) {
3290 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003291 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003292 node1 = node1->parent;
3293 }
3294 if (node2->type == XML_ATTRIBUTE_NODE) {
3295 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003296 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003297 node2 = node2->parent;
3298 }
3299 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00003300 if (attr1 == attr2) {
3301 /* not required, but we keep attributes in order */
3302 if (attr1 != 0) {
3303 cur = attrNode2->prev;
3304 while (cur != NULL) {
3305 if (cur == attrNode1)
3306 return (1);
3307 cur = cur->prev;
3308 }
3309 return (-1);
3310 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003311 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00003312 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003313 if (attr2 == 1)
3314 return(1);
3315 return(-1);
3316 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003317 if ((node1->type == XML_NAMESPACE_DECL) ||
3318 (node2->type == XML_NAMESPACE_DECL))
3319 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003320 if (node1 == node2->prev)
3321 return(1);
3322 if (node1 == node2->next)
3323 return(-1);
3324
3325 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003326 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003327 */
3328 if ((node1->type == XML_ELEMENT_NODE) &&
3329 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003330 (0 > (long) node1->content) &&
3331 (0 > (long) node2->content) &&
3332 (node1->doc == node2->doc)) {
3333 long l1, l2;
3334
3335 l1 = -((long) node1->content);
3336 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003337 if (l1 < l2)
3338 return(1);
3339 if (l1 > l2)
3340 return(-1);
3341 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003342
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003343 /*
Owen Taylor3473f882001-02-23 17:55:21 +00003344 * compute depth to root
3345 */
3346 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003347 if (cur->parent == node1)
Owen Taylor3473f882001-02-23 17:55:21 +00003348 return(1);
3349 depth2++;
3350 }
3351 root = cur;
3352 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003353 if (cur->parent == node2)
Owen Taylor3473f882001-02-23 17:55:21 +00003354 return(-1);
3355 depth1++;
3356 }
3357 /*
3358 * Distinct document (or distinct entities :-( ) case.
3359 */
3360 if (root != cur) {
3361 return(-2);
3362 }
3363 /*
3364 * get the nearest common ancestor.
3365 */
3366 while (depth1 > depth2) {
3367 depth1--;
3368 node1 = node1->parent;
3369 }
3370 while (depth2 > depth1) {
3371 depth2--;
3372 node2 = node2->parent;
3373 }
3374 while (node1->parent != node2->parent) {
3375 node1 = node1->parent;
3376 node2 = node2->parent;
3377 /* should not happen but just in case ... */
3378 if ((node1 == NULL) || (node2 == NULL))
3379 return(-2);
3380 }
3381 /*
3382 * Find who's first.
3383 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003384 if (node1 == node2->prev)
3385 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003386 if (node1 == node2->next)
3387 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003388 /*
3389 * Speedup using document order if availble.
3390 */
3391 if ((node1->type == XML_ELEMENT_NODE) &&
3392 (node2->type == XML_ELEMENT_NODE) &&
3393 (0 > (long) node1->content) &&
3394 (0 > (long) node2->content) &&
3395 (node1->doc == node2->doc)) {
3396 long l1, l2;
3397
3398 l1 = -((long) node1->content);
3399 l2 = -((long) node2->content);
3400 if (l1 < l2)
3401 return(1);
3402 if (l1 > l2)
3403 return(-1);
3404 }
3405
Owen Taylor3473f882001-02-23 17:55:21 +00003406 for (cur = node1->next;cur != NULL;cur = cur->next)
3407 if (cur == node2)
3408 return(1);
3409 return(-1); /* assume there is no sibling list corruption */
3410}
3411
3412/**
3413 * xmlXPathNodeSetSort:
3414 * @set: the node set
3415 *
3416 * Sort the node set in document order
3417 */
3418void
3419xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Vojtech Fried3e031b72012-08-24 16:52:44 +08003420#ifndef WITH_TIM_SORT
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003421 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003422 xmlNodePtr tmp;
Vojtech Fried3e031b72012-08-24 16:52:44 +08003423#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003424
3425 if (set == NULL)
3426 return;
3427
Vojtech Fried3e031b72012-08-24 16:52:44 +08003428#ifndef WITH_TIM_SORT
3429 /*
3430 * Use the old Shell's sort implementation to sort the node-set
3431 * Timsort ought to be quite faster
3432 */
Owen Taylor3473f882001-02-23 17:55:21 +00003433 len = set->nodeNr;
3434 for (incr = len / 2; incr > 0; incr /= 2) {
3435 for (i = incr; i < len; i++) {
3436 j = i - incr;
3437 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003438#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003439 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3440 set->nodeTab[j + incr]) == -1)
3441#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003442 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003443 set->nodeTab[j + incr]) == -1)
3444#endif
3445 {
Owen Taylor3473f882001-02-23 17:55:21 +00003446 tmp = set->nodeTab[j];
3447 set->nodeTab[j] = set->nodeTab[j + incr];
3448 set->nodeTab[j + incr] = tmp;
3449 j -= incr;
3450 } else
3451 break;
3452 }
3453 }
3454 }
Vojtech Fried3e031b72012-08-24 16:52:44 +08003455#else /* WITH_TIM_SORT */
3456 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3457#endif /* WITH_TIM_SORT */
Owen Taylor3473f882001-02-23 17:55:21 +00003458}
3459
3460#define XML_NODESET_DEFAULT 10
3461/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003462 * xmlXPathNodeSetDupNs:
3463 * @node: the parent node of the namespace XPath node
3464 * @ns: the libxml namespace declaration node.
3465 *
3466 * Namespace node in libxml don't match the XPath semantic. In a node set
3467 * the namespace nodes are duplicated and the next pointer is set to the
3468 * parent node in the XPath semantic.
3469 *
3470 * Returns the newly created object.
3471 */
3472static xmlNodePtr
3473xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3474 xmlNsPtr cur;
3475
3476 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3477 return(NULL);
3478 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3479 return((xmlNodePtr) ns);
3480
3481 /*
3482 * Allocate a new Namespace and fill the fields.
3483 */
3484 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3485 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003486 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003487 return(NULL);
3488 }
3489 memset(cur, 0, sizeof(xmlNs));
3490 cur->type = XML_NAMESPACE_DECL;
3491 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003492 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003493 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003494 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003495 cur->next = (xmlNsPtr) node;
3496 return((xmlNodePtr) cur);
3497}
3498
3499/**
3500 * xmlXPathNodeSetFreeNs:
3501 * @ns: the XPath namespace node found in a nodeset.
3502 *
William M. Brack08171912003-12-29 02:52:11 +00003503 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003504 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003505 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003506 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003507void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003508xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3509 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3510 return;
3511
3512 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3513 if (ns->href != NULL)
3514 xmlFree((xmlChar *)ns->href);
3515 if (ns->prefix != NULL)
3516 xmlFree((xmlChar *)ns->prefix);
3517 xmlFree(ns);
3518 }
3519}
3520
3521/**
Owen Taylor3473f882001-02-23 17:55:21 +00003522 * xmlXPathNodeSetCreate:
3523 * @val: an initial xmlNodePtr, or NULL
3524 *
3525 * Create a new xmlNodeSetPtr of type double and of value @val
3526 *
3527 * Returns the newly created object.
3528 */
3529xmlNodeSetPtr
3530xmlXPathNodeSetCreate(xmlNodePtr val) {
3531 xmlNodeSetPtr ret;
3532
3533 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3534 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003535 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003536 return(NULL);
3537 }
3538 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3539 if (val != NULL) {
3540 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3541 sizeof(xmlNodePtr));
3542 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003543 xmlXPathErrMemory(NULL, "creating nodeset\n");
3544 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003545 return(NULL);
3546 }
3547 memset(ret->nodeTab, 0 ,
3548 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3549 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003550 if (val->type == XML_NAMESPACE_DECL) {
3551 xmlNsPtr ns = (xmlNsPtr) val;
3552
3553 ret->nodeTab[ret->nodeNr++] =
3554 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3555 } else
3556 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003557 }
3558 return(ret);
3559}
3560
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003561/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003562 * xmlXPathNodeSetCreateSize:
3563 * @size: the initial size of the set
3564 *
3565 * Create a new xmlNodeSetPtr of type double and of value @val
3566 *
3567 * Returns the newly created object.
3568 */
3569static xmlNodeSetPtr
3570xmlXPathNodeSetCreateSize(int size) {
3571 xmlNodeSetPtr ret;
3572
3573 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3574 if (ret == NULL) {
3575 xmlXPathErrMemory(NULL, "creating nodeset\n");
3576 return(NULL);
3577 }
3578 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3579 if (size < XML_NODESET_DEFAULT)
3580 size = XML_NODESET_DEFAULT;
3581 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3582 if (ret->nodeTab == NULL) {
3583 xmlXPathErrMemory(NULL, "creating nodeset\n");
3584 xmlFree(ret);
3585 return(NULL);
3586 }
3587 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003588 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003589 return(ret);
3590}
3591
3592/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003593 * xmlXPathNodeSetContains:
3594 * @cur: the node-set
3595 * @val: the node
3596 *
3597 * checks whether @cur contains @val
3598 *
3599 * Returns true (1) if @cur contains @val, false (0) otherwise
3600 */
3601int
3602xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3603 int i;
3604
Daniel Veillarda82b1822004-11-08 16:24:57 +00003605 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003606 if (val->type == XML_NAMESPACE_DECL) {
3607 for (i = 0; i < cur->nodeNr; i++) {
3608 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3609 xmlNsPtr ns1, ns2;
3610
3611 ns1 = (xmlNsPtr) val;
3612 ns2 = (xmlNsPtr) cur->nodeTab[i];
3613 if (ns1 == ns2)
3614 return(1);
3615 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3616 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3617 return(1);
3618 }
3619 }
3620 } else {
3621 for (i = 0; i < cur->nodeNr; i++) {
3622 if (cur->nodeTab[i] == val)
3623 return(1);
3624 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003625 }
3626 return(0);
3627}
3628
3629/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003630 * xmlXPathNodeSetAddNs:
3631 * @cur: the initial node set
3632 * @node: the hosting node
3633 * @ns: a the namespace node
3634 *
3635 * add a new namespace node to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003636 *
3637 * Returns 0 in case of success and -1 in case of error
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003638 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003639int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003640xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3641 int i;
3642
Daniel Veillard45490ae2008-07-29 09:13:19 +00003643
Daniel Veillarda82b1822004-11-08 16:24:57 +00003644 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3645 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003646 (node->type != XML_ELEMENT_NODE))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003647 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003648
William M. Brack08171912003-12-29 02:52:11 +00003649 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003650 /*
William M. Brack08171912003-12-29 02:52:11 +00003651 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003652 */
3653 for (i = 0;i < cur->nodeNr;i++) {
3654 if ((cur->nodeTab[i] != NULL) &&
3655 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003656 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003657 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003658 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003659 }
3660
3661 /*
3662 * grow the nodeTab if needed
3663 */
3664 if (cur->nodeMax == 0) {
3665 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3666 sizeof(xmlNodePtr));
3667 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003668 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003669 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003670 }
3671 memset(cur->nodeTab, 0 ,
3672 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3673 cur->nodeMax = XML_NODESET_DEFAULT;
3674 } else if (cur->nodeNr == cur->nodeMax) {
3675 xmlNodePtr *temp;
3676
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003677 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3678 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003679 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003680 }
Chris Evansd7958b22011-03-23 08:13:06 +08003681 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003682 sizeof(xmlNodePtr));
3683 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003684 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003685 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003686 }
Chris Evansd7958b22011-03-23 08:13:06 +08003687 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003688 cur->nodeTab = temp;
3689 }
3690 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003691 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003692}
3693
3694/**
Owen Taylor3473f882001-02-23 17:55:21 +00003695 * xmlXPathNodeSetAdd:
3696 * @cur: the initial node set
3697 * @val: a new xmlNodePtr
3698 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003699 * add a new xmlNodePtr to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003700 *
3701 * Returns 0 in case of success, and -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00003702 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003703int
Owen Taylor3473f882001-02-23 17:55:21 +00003704xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3705 int i;
3706
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003707 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003708
William M. Brack08171912003-12-29 02:52:11 +00003709 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003710 /*
Shlomi Fishd5bd2a92016-04-03 05:14:44 +03003711 * prevent duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003712 */
3713 for (i = 0;i < cur->nodeNr;i++)
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003714 if (cur->nodeTab[i] == val) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003715
3716 /*
3717 * grow the nodeTab if needed
3718 */
3719 if (cur->nodeMax == 0) {
3720 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3721 sizeof(xmlNodePtr));
3722 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003723 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003724 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003725 }
3726 memset(cur->nodeTab, 0 ,
3727 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3728 cur->nodeMax = XML_NODESET_DEFAULT;
3729 } else if (cur->nodeNr == cur->nodeMax) {
3730 xmlNodePtr *temp;
3731
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003732 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3733 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003734 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003735 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003736 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003737 sizeof(xmlNodePtr));
3738 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003739 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003740 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003741 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003742 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003743 cur->nodeTab = temp;
3744 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003745 if (val->type == XML_NAMESPACE_DECL) {
3746 xmlNsPtr ns = (xmlNsPtr) val;
3747
Daniel Veillard45490ae2008-07-29 09:13:19 +00003748 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003749 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3750 } else
3751 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003752 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003753}
3754
3755/**
3756 * xmlXPathNodeSetAddUnique:
3757 * @cur: the initial node set
3758 * @val: a new xmlNodePtr
3759 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003760 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003761 * when we are sure the node is not already in the set.
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003762 *
3763 * Returns 0 in case of success and -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00003764 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003765int
Owen Taylor3473f882001-02-23 17:55:21 +00003766xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003767 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003768
William M. Brack08171912003-12-29 02:52:11 +00003769 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003770 /*
3771 * grow the nodeTab if needed
3772 */
3773 if (cur->nodeMax == 0) {
3774 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3775 sizeof(xmlNodePtr));
3776 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003777 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003778 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003779 }
3780 memset(cur->nodeTab, 0 ,
3781 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3782 cur->nodeMax = XML_NODESET_DEFAULT;
3783 } else if (cur->nodeNr == cur->nodeMax) {
3784 xmlNodePtr *temp;
3785
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003786 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3787 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003788 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003789 }
Chris Evansd7958b22011-03-23 08:13:06 +08003790 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003791 sizeof(xmlNodePtr));
3792 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003793 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003794 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003795 }
3796 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003797 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003798 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003799 if (val->type == XML_NAMESPACE_DECL) {
3800 xmlNsPtr ns = (xmlNsPtr) val;
3801
Daniel Veillard45490ae2008-07-29 09:13:19 +00003802 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003803 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3804 } else
3805 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003806 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003807}
3808
3809/**
3810 * xmlXPathNodeSetMerge:
3811 * @val1: the first NodeSet or NULL
3812 * @val2: the second NodeSet
3813 *
3814 * Merges two nodesets, all nodes from @val2 are added to @val1
3815 * if @val1 is NULL, a new set is created and copied from @val2
3816 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003817 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003818 */
3819xmlNodeSetPtr
3820xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003821 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003822 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003823
3824 if (val2 == NULL) return(val1);
3825 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003826 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003827 if (val1 == NULL)
3828 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003829#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003830 /*
3831 * TODO: The optimization won't work in every case, since
3832 * those nasty namespace nodes need to be added with
3833 * xmlXPathNodeSetDupNs() to the set; thus a pure
3834 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003835 * If there was a flag on the nodesetval, indicating that
3836 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003837 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003838 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003839 * Optimization: Create an equally sized node-set
3840 * and memcpy the content.
3841 */
3842 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3843 if (val1 == NULL)
3844 return(NULL);
3845 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003846 if (val2->nodeNr == 1)
3847 *(val1->nodeTab) = *(val2->nodeTab);
3848 else {
3849 memcpy(val1->nodeTab, val2->nodeTab,
3850 val2->nodeNr * sizeof(xmlNodePtr));
3851 }
3852 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003853 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003854 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003855#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003856 }
3857
William M. Brack08171912003-12-29 02:52:11 +00003858 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003859 initNr = val1->nodeNr;
3860
3861 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003862 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003863 /*
William M. Brack08171912003-12-29 02:52:11 +00003864 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003865 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003866 skip = 0;
3867 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003868 n1 = val1->nodeTab[j];
3869 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003870 skip = 1;
3871 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003872 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003873 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003874 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3875 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3876 ((xmlNsPtr) n2)->prefix)))
3877 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003878 skip = 1;
3879 break;
3880 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003881 }
3882 }
3883 if (skip)
3884 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003885
3886 /*
3887 * grow the nodeTab if needed
3888 */
3889 if (val1->nodeMax == 0) {
3890 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3891 sizeof(xmlNodePtr));
3892 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003893 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003894 return(NULL);
3895 }
3896 memset(val1->nodeTab, 0 ,
3897 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3898 val1->nodeMax = XML_NODESET_DEFAULT;
3899 } else if (val1->nodeNr == val1->nodeMax) {
3900 xmlNodePtr *temp;
3901
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003902 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3903 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3904 return(NULL);
3905 }
Chris Evansd7958b22011-03-23 08:13:06 +08003906 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003907 sizeof(xmlNodePtr));
3908 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003909 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003910 return(NULL);
3911 }
3912 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003913 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003914 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003915 if (n2->type == XML_NAMESPACE_DECL) {
3916 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003917
3918 val1->nodeTab[val1->nodeNr++] =
3919 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3920 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003921 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003922 }
3923
3924 return(val1);
3925}
3926
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003927
3928/**
3929 * xmlXPathNodeSetMergeAndClear:
3930 * @set1: the first NodeSet or NULL
3931 * @set2: the second NodeSet
3932 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3933 *
3934 * Merges two nodesets, all nodes from @set2 are added to @set1
3935 * if @set1 is NULL, a new set is created and copied from @set2.
3936 * Checks for duplicate nodes. Clears set2.
3937 *
3938 * Returns @set1 once extended or NULL in case of error.
3939 */
3940static xmlNodeSetPtr
3941xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3942 int hasNullEntries)
3943{
3944 if ((set1 == NULL) && (hasNullEntries == 0)) {
3945 /*
3946 * Note that doing a memcpy of the list, namespace nodes are
3947 * just assigned to set1, since set2 is cleared anyway.
3948 */
3949 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3950 if (set1 == NULL)
3951 return(NULL);
3952 if (set2->nodeNr != 0) {
3953 memcpy(set1->nodeTab, set2->nodeTab,
3954 set2->nodeNr * sizeof(xmlNodePtr));
3955 set1->nodeNr = set2->nodeNr;
3956 }
3957 } else {
3958 int i, j, initNbSet1;
3959 xmlNodePtr n1, n2;
3960
3961 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003962 set1 = xmlXPathNodeSetCreate(NULL);
3963 if (set1 == NULL)
3964 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003965
Daniel Veillard45490ae2008-07-29 09:13:19 +00003966 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003967 for (i = 0;i < set2->nodeNr;i++) {
3968 n2 = set2->nodeTab[i];
3969 /*
3970 * Skip NULLed entries.
3971 */
3972 if (n2 == NULL)
3973 continue;
3974 /*
3975 * Skip duplicates.
3976 */
3977 for (j = 0; j < initNbSet1; j++) {
3978 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003979 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003980 goto skip_node;
3981 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3982 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003983 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003984 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3985 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3986 ((xmlNsPtr) n2)->prefix)))
3987 {
3988 /*
3989 * Free the namespace node.
3990 */
3991 set2->nodeTab[i] = NULL;
3992 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3993 goto skip_node;
3994 }
3995 }
3996 }
3997 /*
3998 * grow the nodeTab if needed
3999 */
4000 if (set1->nodeMax == 0) {
4001 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4002 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4003 if (set1->nodeTab == NULL) {
4004 xmlXPathErrMemory(NULL, "merging nodeset\n");
4005 return(NULL);
4006 }
4007 memset(set1->nodeTab, 0,
4008 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4009 set1->nodeMax = XML_NODESET_DEFAULT;
4010 } else if (set1->nodeNr >= set1->nodeMax) {
4011 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004012
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004013 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4014 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4015 return(NULL);
4016 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004017 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004018 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004019 if (temp == NULL) {
4020 xmlXPathErrMemory(NULL, "merging nodeset\n");
4021 return(NULL);
4022 }
4023 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004024 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004025 }
Nick Wellnhofer9d08b342017-05-21 16:46:12 +02004026 set1->nodeTab[set1->nodeNr++] = n2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004027skip_node:
4028 {}
4029 }
4030 }
4031 set2->nodeNr = 0;
4032 return(set1);
4033}
4034
4035/**
4036 * xmlXPathNodeSetMergeAndClearNoDupls:
4037 * @set1: the first NodeSet or NULL
4038 * @set2: the second NodeSet
4039 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4040 *
4041 * Merges two nodesets, all nodes from @set2 are added to @set1
4042 * if @set1 is NULL, a new set is created and copied from @set2.
4043 * Doesn't chack for duplicate nodes. Clears set2.
4044 *
4045 * Returns @set1 once extended or NULL in case of error.
4046 */
4047static xmlNodeSetPtr
4048xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4049 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004050{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004051 if (set2 == NULL)
4052 return(set1);
4053 if ((set1 == NULL) && (hasNullEntries == 0)) {
4054 /*
4055 * Note that doing a memcpy of the list, namespace nodes are
4056 * just assigned to set1, since set2 is cleared anyway.
4057 */
4058 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4059 if (set1 == NULL)
4060 return(NULL);
4061 if (set2->nodeNr != 0) {
4062 memcpy(set1->nodeTab, set2->nodeTab,
4063 set2->nodeNr * sizeof(xmlNodePtr));
4064 set1->nodeNr = set2->nodeNr;
4065 }
4066 } else {
4067 int i;
4068 xmlNodePtr n2;
4069
4070 if (set1 == NULL)
4071 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004072 if (set1 == NULL)
4073 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004074
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004075 for (i = 0;i < set2->nodeNr;i++) {
4076 n2 = set2->nodeTab[i];
4077 /*
4078 * Skip NULLed entries.
4079 */
4080 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004081 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004082 if (set1->nodeMax == 0) {
4083 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4084 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4085 if (set1->nodeTab == NULL) {
4086 xmlXPathErrMemory(NULL, "merging nodeset\n");
4087 return(NULL);
4088 }
4089 memset(set1->nodeTab, 0,
4090 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4091 set1->nodeMax = XML_NODESET_DEFAULT;
4092 } else if (set1->nodeNr >= set1->nodeMax) {
4093 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004094
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004095 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4096 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4097 return(NULL);
4098 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004099 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004100 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004101 if (temp == NULL) {
4102 xmlXPathErrMemory(NULL, "merging nodeset\n");
4103 return(NULL);
4104 }
4105 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004106 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004107 }
4108 set1->nodeTab[set1->nodeNr++] = n2;
4109 }
4110 }
4111 set2->nodeNr = 0;
4112 return(set1);
4113}
Daniel Veillard75be0132002-03-13 10:03:35 +00004114
4115/**
Owen Taylor3473f882001-02-23 17:55:21 +00004116 * xmlXPathNodeSetDel:
4117 * @cur: the initial node set
4118 * @val: an xmlNodePtr
4119 *
4120 * Removes an xmlNodePtr from an existing NodeSet
4121 */
4122void
4123xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4124 int i;
4125
4126 if (cur == NULL) return;
4127 if (val == NULL) return;
4128
4129 /*
William M. Brack08171912003-12-29 02:52:11 +00004130 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004131 */
4132 for (i = 0;i < cur->nodeNr;i++)
4133 if (cur->nodeTab[i] == val) break;
4134
William M. Brack08171912003-12-29 02:52:11 +00004135 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004136#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004137 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004138 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4139 val->name);
4140#endif
4141 return;
4142 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004143 if ((cur->nodeTab[i] != NULL) &&
4144 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4145 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004146 cur->nodeNr--;
4147 for (;i < cur->nodeNr;i++)
4148 cur->nodeTab[i] = cur->nodeTab[i + 1];
4149 cur->nodeTab[cur->nodeNr] = NULL;
4150}
4151
4152/**
4153 * xmlXPathNodeSetRemove:
4154 * @cur: the initial node set
4155 * @val: the index to remove
4156 *
4157 * Removes an entry from an existing NodeSet list.
4158 */
4159void
4160xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4161 if (cur == NULL) return;
4162 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004163 if ((cur->nodeTab[val] != NULL) &&
4164 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4165 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004166 cur->nodeNr--;
4167 for (;val < cur->nodeNr;val++)
4168 cur->nodeTab[val] = cur->nodeTab[val + 1];
4169 cur->nodeTab[cur->nodeNr] = NULL;
4170}
4171
4172/**
4173 * xmlXPathFreeNodeSet:
4174 * @obj: the xmlNodeSetPtr to free
4175 *
4176 * Free the NodeSet compound (not the actual nodes !).
4177 */
4178void
4179xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4180 if (obj == NULL) return;
4181 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004182 int i;
4183
William M. Brack08171912003-12-29 02:52:11 +00004184 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004185 for (i = 0;i < obj->nodeNr;i++)
4186 if ((obj->nodeTab[i] != NULL) &&
4187 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4188 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004189 xmlFree(obj->nodeTab);
4190 }
Owen Taylor3473f882001-02-23 17:55:21 +00004191 xmlFree(obj);
4192}
4193
4194/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004195 * xmlXPathNodeSetClearFromPos:
4196 * @set: the node set to be cleared
4197 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004198 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004199 * Clears the list from temporary XPath objects (e.g. namespace nodes
4200 * are feed) starting with the entry at @pos, but does *not* free the list
4201 * itself. Sets the length of the list to @pos.
4202 */
4203static void
4204xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4205{
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004206 if ((set == NULL) || (pos >= set->nodeNr))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004207 return;
4208 else if ((hasNsNodes)) {
4209 int i;
4210 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004211
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004212 for (i = pos; i < set->nodeNr; i++) {
4213 node = set->nodeTab[i];
4214 if ((node != NULL) &&
4215 (node->type == XML_NAMESPACE_DECL))
4216 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004217 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004218 }
4219 set->nodeNr = pos;
4220}
4221
4222/**
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004223 * xmlXPathNodeSetClear:
4224 * @set: the node set to clear
4225 *
4226 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4227 * are feed), but does *not* free the list itself. Sets the length of the
4228 * list to 0.
4229 */
4230static void
4231xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4232{
4233 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4234}
4235
4236/**
4237 * xmlXPathNodeSetKeepLast:
4238 * @set: the node set to be cleared
4239 *
4240 * Move the last node to the first position and clear temporary XPath objects
4241 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4242 * to 1.
4243 */
4244static void
4245xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4246{
4247 int i;
4248 xmlNodePtr node;
4249
4250 if ((set == NULL) || (set->nodeNr <= 1))
4251 return;
4252 for (i = 0; i < set->nodeNr - 1; i++) {
4253 node = set->nodeTab[i];
4254 if ((node != NULL) &&
4255 (node->type == XML_NAMESPACE_DECL))
4256 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4257 }
4258 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4259 set->nodeNr = 1;
4260}
4261
4262/**
Owen Taylor3473f882001-02-23 17:55:21 +00004263 * xmlXPathFreeValueTree:
4264 * @obj: the xmlNodeSetPtr to free
4265 *
4266 * Free the NodeSet compound and the actual tree, this is different
4267 * from xmlXPathFreeNodeSet()
4268 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004269static void
Owen Taylor3473f882001-02-23 17:55:21 +00004270xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4271 int i;
4272
4273 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004274
4275 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004276 for (i = 0;i < obj->nodeNr;i++) {
4277 if (obj->nodeTab[i] != NULL) {
4278 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4279 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4280 } else {
4281 xmlFreeNodeList(obj->nodeTab[i]);
4282 }
4283 }
4284 }
Owen Taylor3473f882001-02-23 17:55:21 +00004285 xmlFree(obj->nodeTab);
4286 }
Owen Taylor3473f882001-02-23 17:55:21 +00004287 xmlFree(obj);
4288}
4289
4290#if defined(DEBUG) || defined(DEBUG_STEP)
4291/**
4292 * xmlGenericErrorContextNodeSet:
4293 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004294 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004295 *
4296 * Quick display of a NodeSet
4297 */
4298void
4299xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4300 int i;
4301
4302 if (output == NULL) output = xmlGenericErrorContext;
4303 if (obj == NULL) {
4304 fprintf(output, "NodeSet == NULL !\n");
4305 return;
4306 }
4307 if (obj->nodeNr == 0) {
4308 fprintf(output, "NodeSet is empty\n");
4309 return;
4310 }
4311 if (obj->nodeTab == NULL) {
4312 fprintf(output, " nodeTab == NULL !\n");
4313 return;
4314 }
4315 for (i = 0; i < obj->nodeNr; i++) {
4316 if (obj->nodeTab[i] == NULL) {
4317 fprintf(output, " NULL !\n");
4318 return;
4319 }
4320 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4321 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4322 fprintf(output, " /");
4323 else if (obj->nodeTab[i]->name == NULL)
4324 fprintf(output, " noname!");
4325 else fprintf(output, " %s", obj->nodeTab[i]->name);
4326 }
4327 fprintf(output, "\n");
4328}
4329#endif
4330
4331/**
4332 * xmlXPathNewNodeSet:
4333 * @val: the NodePtr value
4334 *
4335 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4336 * it with the single Node @val
4337 *
4338 * Returns the newly created object.
4339 */
4340xmlXPathObjectPtr
4341xmlXPathNewNodeSet(xmlNodePtr val) {
4342 xmlXPathObjectPtr ret;
4343
4344 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4345 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004346 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004347 return(NULL);
4348 }
4349 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4350 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004351 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004352 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004353 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004354#ifdef XP_DEBUG_OBJ_USAGE
4355 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4356#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004357 return(ret);
4358}
4359
4360/**
4361 * xmlXPathNewValueTree:
4362 * @val: the NodePtr value
4363 *
4364 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4365 * it with the tree root @val
4366 *
4367 * Returns the newly created object.
4368 */
4369xmlXPathObjectPtr
4370xmlXPathNewValueTree(xmlNodePtr val) {
4371 xmlXPathObjectPtr ret;
4372
4373 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4374 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004375 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004376 return(NULL);
4377 }
4378 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4379 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004380 ret->boolval = 1;
4381 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004382 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004383#ifdef XP_DEBUG_OBJ_USAGE
4384 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4385#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004386 return(ret);
4387}
4388
4389/**
4390 * xmlXPathNewNodeSetList:
4391 * @val: an existing NodeSet
4392 *
4393 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4394 * it with the Nodeset @val
4395 *
4396 * Returns the newly created object.
4397 */
4398xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004399xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4400{
Owen Taylor3473f882001-02-23 17:55:21 +00004401 xmlXPathObjectPtr ret;
4402 int i;
4403
4404 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004405 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004406 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004407 ret = xmlXPathNewNodeSet(NULL);
4408 else {
4409 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004410 if (ret) {
4411 for (i = 1; i < val->nodeNr; ++i) {
4412 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4413 < 0) break;
4414 }
4415 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004416 }
Owen Taylor3473f882001-02-23 17:55:21 +00004417
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004418 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004419}
4420
4421/**
4422 * xmlXPathWrapNodeSet:
4423 * @val: the NodePtr value
4424 *
4425 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4426 *
4427 * Returns the newly created object.
4428 */
4429xmlXPathObjectPtr
4430xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4431 xmlXPathObjectPtr ret;
4432
4433 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4434 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004435 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004436 return(NULL);
4437 }
4438 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4439 ret->type = XPATH_NODESET;
4440 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004441#ifdef XP_DEBUG_OBJ_USAGE
4442 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4443#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004444 return(ret);
4445}
4446
4447/**
4448 * xmlXPathFreeNodeSetList:
4449 * @obj: an existing NodeSetList object
4450 *
4451 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4452 * the list contrary to xmlXPathFreeObject().
4453 */
4454void
4455xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4456 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004457#ifdef XP_DEBUG_OBJ_USAGE
4458 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4459#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004460 xmlFree(obj);
4461}
4462
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004463/**
4464 * xmlXPathDifference:
4465 * @nodes1: a node-set
4466 * @nodes2: a node-set
4467 *
4468 * Implements the EXSLT - Sets difference() function:
4469 * node-set set:difference (node-set, node-set)
4470 *
4471 * Returns the difference between the two node sets, or nodes1 if
4472 * nodes2 is empty
4473 */
4474xmlNodeSetPtr
4475xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4476 xmlNodeSetPtr ret;
4477 int i, l1;
4478 xmlNodePtr cur;
4479
4480 if (xmlXPathNodeSetIsEmpty(nodes2))
4481 return(nodes1);
4482
4483 ret = xmlXPathNodeSetCreate(NULL);
4484 if (xmlXPathNodeSetIsEmpty(nodes1))
4485 return(ret);
4486
4487 l1 = xmlXPathNodeSetGetLength(nodes1);
4488
4489 for (i = 0; i < l1; i++) {
4490 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004491 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4492 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4493 break;
4494 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004495 }
4496 return(ret);
4497}
4498
4499/**
4500 * xmlXPathIntersection:
4501 * @nodes1: a node-set
4502 * @nodes2: a node-set
4503 *
4504 * Implements the EXSLT - Sets intersection() function:
4505 * node-set set:intersection (node-set, node-set)
4506 *
4507 * Returns a node set comprising the nodes that are within both the
4508 * node sets passed as arguments
4509 */
4510xmlNodeSetPtr
4511xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4512 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4513 int i, l1;
4514 xmlNodePtr cur;
4515
Daniel Veillardf88d8492008-04-01 08:00:31 +00004516 if (ret == NULL)
4517 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004518 if (xmlXPathNodeSetIsEmpty(nodes1))
4519 return(ret);
4520 if (xmlXPathNodeSetIsEmpty(nodes2))
4521 return(ret);
4522
4523 l1 = xmlXPathNodeSetGetLength(nodes1);
4524
4525 for (i = 0; i < l1; i++) {
4526 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004527 if (xmlXPathNodeSetContains(nodes2, cur)) {
4528 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4529 break;
4530 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004531 }
4532 return(ret);
4533}
4534
4535/**
4536 * xmlXPathDistinctSorted:
4537 * @nodes: a node-set, sorted by document order
4538 *
4539 * Implements the EXSLT - Sets distinct() function:
4540 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004541 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004542 * Returns a subset of the nodes contained in @nodes, or @nodes if
4543 * it is empty
4544 */
4545xmlNodeSetPtr
4546xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4547 xmlNodeSetPtr ret;
4548 xmlHashTablePtr hash;
4549 int i, l;
4550 xmlChar * strval;
4551 xmlNodePtr cur;
4552
4553 if (xmlXPathNodeSetIsEmpty(nodes))
4554 return(nodes);
4555
4556 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004557 if (ret == NULL)
4558 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004559 l = xmlXPathNodeSetGetLength(nodes);
4560 hash = xmlHashCreate (l);
4561 for (i = 0; i < l; i++) {
4562 cur = xmlXPathNodeSetItem(nodes, i);
4563 strval = xmlXPathCastNodeToString(cur);
4564 if (xmlHashLookup(hash, strval) == NULL) {
4565 xmlHashAddEntry(hash, strval, strval);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004566 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4567 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004568 } else {
4569 xmlFree(strval);
4570 }
4571 }
4572 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4573 return(ret);
4574}
4575
4576/**
4577 * xmlXPathDistinct:
4578 * @nodes: a node-set
4579 *
4580 * Implements the EXSLT - Sets distinct() function:
4581 * node-set set:distinct (node-set)
4582 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4583 * is called with the sorted node-set
4584 *
4585 * Returns a subset of the nodes contained in @nodes, or @nodes if
4586 * it is empty
4587 */
4588xmlNodeSetPtr
4589xmlXPathDistinct (xmlNodeSetPtr nodes) {
4590 if (xmlXPathNodeSetIsEmpty(nodes))
4591 return(nodes);
4592
4593 xmlXPathNodeSetSort(nodes);
4594 return(xmlXPathDistinctSorted(nodes));
4595}
4596
4597/**
4598 * xmlXPathHasSameNodes:
4599 * @nodes1: a node-set
4600 * @nodes2: a node-set
4601 *
4602 * Implements the EXSLT - Sets has-same-nodes function:
4603 * boolean set:has-same-node(node-set, node-set)
4604 *
4605 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4606 * otherwise
4607 */
4608int
4609xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4610 int i, l;
4611 xmlNodePtr cur;
4612
4613 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4614 xmlXPathNodeSetIsEmpty(nodes2))
4615 return(0);
4616
4617 l = xmlXPathNodeSetGetLength(nodes1);
4618 for (i = 0; i < l; i++) {
4619 cur = xmlXPathNodeSetItem(nodes1, i);
4620 if (xmlXPathNodeSetContains(nodes2, cur))
4621 return(1);
4622 }
4623 return(0);
4624}
4625
4626/**
4627 * xmlXPathNodeLeadingSorted:
4628 * @nodes: a node-set, sorted by document order
4629 * @node: a node
4630 *
4631 * Implements the EXSLT - Sets leading() function:
4632 * node-set set:leading (node-set, node-set)
4633 *
4634 * Returns the nodes in @nodes that precede @node in document order,
4635 * @nodes if @node is NULL or an empty node-set if @nodes
4636 * doesn't contain @node
4637 */
4638xmlNodeSetPtr
4639xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4640 int i, l;
4641 xmlNodePtr cur;
4642 xmlNodeSetPtr ret;
4643
4644 if (node == NULL)
4645 return(nodes);
4646
4647 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004648 if (ret == NULL)
4649 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004650 if (xmlXPathNodeSetIsEmpty(nodes) ||
4651 (!xmlXPathNodeSetContains(nodes, node)))
4652 return(ret);
4653
4654 l = xmlXPathNodeSetGetLength(nodes);
4655 for (i = 0; i < l; i++) {
4656 cur = xmlXPathNodeSetItem(nodes, i);
4657 if (cur == node)
4658 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004659 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4660 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004661 }
4662 return(ret);
4663}
4664
4665/**
4666 * xmlXPathNodeLeading:
4667 * @nodes: a node-set
4668 * @node: a node
4669 *
4670 * Implements the EXSLT - Sets leading() function:
4671 * node-set set:leading (node-set, node-set)
4672 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4673 * is called.
4674 *
4675 * Returns the nodes in @nodes that precede @node in document order,
4676 * @nodes if @node is NULL or an empty node-set if @nodes
4677 * doesn't contain @node
4678 */
4679xmlNodeSetPtr
4680xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4681 xmlXPathNodeSetSort(nodes);
4682 return(xmlXPathNodeLeadingSorted(nodes, node));
4683}
4684
4685/**
4686 * xmlXPathLeadingSorted:
4687 * @nodes1: a node-set, sorted by document order
4688 * @nodes2: a node-set, sorted by document order
4689 *
4690 * Implements the EXSLT - Sets leading() function:
4691 * node-set set:leading (node-set, node-set)
4692 *
4693 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4694 * in document order, @nodes1 if @nodes2 is NULL or empty or
4695 * an empty node-set if @nodes1 doesn't contain @nodes2
4696 */
4697xmlNodeSetPtr
4698xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4699 if (xmlXPathNodeSetIsEmpty(nodes2))
4700 return(nodes1);
4701 return(xmlXPathNodeLeadingSorted(nodes1,
4702 xmlXPathNodeSetItem(nodes2, 1)));
4703}
4704
4705/**
4706 * xmlXPathLeading:
4707 * @nodes1: a node-set
4708 * @nodes2: a node-set
4709 *
4710 * Implements the EXSLT - Sets leading() function:
4711 * node-set set:leading (node-set, node-set)
4712 * @nodes1 and @nodes2 are sorted by document order, then
4713 * #exslSetsLeadingSorted is called.
4714 *
4715 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4716 * in document order, @nodes1 if @nodes2 is NULL or empty or
4717 * an empty node-set if @nodes1 doesn't contain @nodes2
4718 */
4719xmlNodeSetPtr
4720xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4721 if (xmlXPathNodeSetIsEmpty(nodes2))
4722 return(nodes1);
4723 if (xmlXPathNodeSetIsEmpty(nodes1))
4724 return(xmlXPathNodeSetCreate(NULL));
4725 xmlXPathNodeSetSort(nodes1);
4726 xmlXPathNodeSetSort(nodes2);
4727 return(xmlXPathNodeLeadingSorted(nodes1,
4728 xmlXPathNodeSetItem(nodes2, 1)));
4729}
4730
4731/**
4732 * xmlXPathNodeTrailingSorted:
4733 * @nodes: a node-set, sorted by document order
4734 * @node: a node
4735 *
4736 * Implements the EXSLT - Sets trailing() function:
4737 * node-set set:trailing (node-set, node-set)
4738 *
4739 * Returns the nodes in @nodes that follow @node in document order,
4740 * @nodes if @node is NULL or an empty node-set if @nodes
4741 * doesn't contain @node
4742 */
4743xmlNodeSetPtr
4744xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4745 int i, l;
4746 xmlNodePtr cur;
4747 xmlNodeSetPtr ret;
4748
4749 if (node == NULL)
4750 return(nodes);
4751
4752 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004753 if (ret == NULL)
4754 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004755 if (xmlXPathNodeSetIsEmpty(nodes) ||
4756 (!xmlXPathNodeSetContains(nodes, node)))
4757 return(ret);
4758
4759 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004760 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004761 cur = xmlXPathNodeSetItem(nodes, i);
4762 if (cur == node)
4763 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004764 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4765 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004766 }
William M. Brack97ac8192007-06-06 17:19:24 +00004767 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004768 return(ret);
4769}
4770
4771/**
4772 * xmlXPathNodeTrailing:
4773 * @nodes: a node-set
4774 * @node: a node
4775 *
4776 * Implements the EXSLT - Sets trailing() function:
4777 * node-set set:trailing (node-set, node-set)
4778 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4779 * is called.
4780 *
4781 * Returns the nodes in @nodes that follow @node in document order,
4782 * @nodes if @node is NULL or an empty node-set if @nodes
4783 * doesn't contain @node
4784 */
4785xmlNodeSetPtr
4786xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4787 xmlXPathNodeSetSort(nodes);
4788 return(xmlXPathNodeTrailingSorted(nodes, node));
4789}
4790
4791/**
4792 * xmlXPathTrailingSorted:
4793 * @nodes1: a node-set, sorted by document order
4794 * @nodes2: a node-set, sorted by document order
4795 *
4796 * Implements the EXSLT - Sets trailing() function:
4797 * node-set set:trailing (node-set, node-set)
4798 *
4799 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4800 * in document order, @nodes1 if @nodes2 is NULL or empty or
4801 * an empty node-set if @nodes1 doesn't contain @nodes2
4802 */
4803xmlNodeSetPtr
4804xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4805 if (xmlXPathNodeSetIsEmpty(nodes2))
4806 return(nodes1);
4807 return(xmlXPathNodeTrailingSorted(nodes1,
4808 xmlXPathNodeSetItem(nodes2, 0)));
4809}
4810
4811/**
4812 * xmlXPathTrailing:
4813 * @nodes1: a node-set
4814 * @nodes2: a node-set
4815 *
4816 * Implements the EXSLT - Sets trailing() function:
4817 * node-set set:trailing (node-set, node-set)
4818 * @nodes1 and @nodes2 are sorted by document order, then
4819 * #xmlXPathTrailingSorted is called.
4820 *
4821 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4822 * in document order, @nodes1 if @nodes2 is NULL or empty or
4823 * an empty node-set if @nodes1 doesn't contain @nodes2
4824 */
4825xmlNodeSetPtr
4826xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4827 if (xmlXPathNodeSetIsEmpty(nodes2))
4828 return(nodes1);
4829 if (xmlXPathNodeSetIsEmpty(nodes1))
4830 return(xmlXPathNodeSetCreate(NULL));
4831 xmlXPathNodeSetSort(nodes1);
4832 xmlXPathNodeSetSort(nodes2);
4833 return(xmlXPathNodeTrailingSorted(nodes1,
4834 xmlXPathNodeSetItem(nodes2, 0)));
4835}
4836
Owen Taylor3473f882001-02-23 17:55:21 +00004837/************************************************************************
4838 * *
4839 * Routines to handle extra functions *
4840 * *
4841 ************************************************************************/
4842
4843/**
4844 * xmlXPathRegisterFunc:
4845 * @ctxt: the XPath context
4846 * @name: the function name
4847 * @f: the function implementation or NULL
4848 *
4849 * Register a new function. If @f is NULL it unregisters the function
4850 *
4851 * Returns 0 in case of success, -1 in case of error
4852 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004853int
Owen Taylor3473f882001-02-23 17:55:21 +00004854xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4855 xmlXPathFunction f) {
4856 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4857}
4858
4859/**
4860 * xmlXPathRegisterFuncNS:
4861 * @ctxt: the XPath context
4862 * @name: the function name
4863 * @ns_uri: the function namespace URI
4864 * @f: the function implementation or NULL
4865 *
4866 * Register a new function. If @f is NULL it unregisters the function
4867 *
4868 * Returns 0 in case of success, -1 in case of error
4869 */
4870int
4871xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4872 const xmlChar *ns_uri, xmlXPathFunction f) {
4873 if (ctxt == NULL)
4874 return(-1);
4875 if (name == NULL)
4876 return(-1);
4877
4878 if (ctxt->funcHash == NULL)
4879 ctxt->funcHash = xmlHashCreate(0);
4880 if (ctxt->funcHash == NULL)
4881 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004882 if (f == NULL)
4883 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004884 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004885}
4886
4887/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004888 * xmlXPathRegisterFuncLookup:
4889 * @ctxt: the XPath context
4890 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004891 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004892 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004893 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004894 */
4895void
4896xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4897 xmlXPathFuncLookupFunc f,
4898 void *funcCtxt) {
4899 if (ctxt == NULL)
4900 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004901 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004902 ctxt->funcLookupData = funcCtxt;
4903}
4904
4905/**
Owen Taylor3473f882001-02-23 17:55:21 +00004906 * xmlXPathFunctionLookup:
4907 * @ctxt: the XPath context
4908 * @name: the function name
4909 *
4910 * Search in the Function array of the context for the given
4911 * function.
4912 *
4913 * Returns the xmlXPathFunction or NULL if not found
4914 */
4915xmlXPathFunction
4916xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004917 if (ctxt == NULL)
4918 return (NULL);
4919
4920 if (ctxt->funcLookupFunc != NULL) {
4921 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004922 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004923
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004924 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004925 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004926 if (ret != NULL)
4927 return(ret);
4928 }
Owen Taylor3473f882001-02-23 17:55:21 +00004929 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4930}
4931
4932/**
4933 * xmlXPathFunctionLookupNS:
4934 * @ctxt: the XPath context
4935 * @name: the function name
4936 * @ns_uri: the function namespace URI
4937 *
4938 * Search in the Function array of the context for the given
4939 * function.
4940 *
4941 * Returns the xmlXPathFunction or NULL if not found
4942 */
4943xmlXPathFunction
4944xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4945 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004946 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004947
Owen Taylor3473f882001-02-23 17:55:21 +00004948 if (ctxt == NULL)
4949 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004950 if (name == NULL)
4951 return(NULL);
4952
Thomas Broyerba4ad322001-07-26 16:55:21 +00004953 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004954 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004955
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004956 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004957 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004958 if (ret != NULL)
4959 return(ret);
4960 }
4961
4962 if (ctxt->funcHash == NULL)
4963 return(NULL);
4964
William M. Brackad0e67c2004-12-01 14:35:10 +00004965 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4966 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004967}
4968
4969/**
4970 * xmlXPathRegisteredFuncsCleanup:
4971 * @ctxt: the XPath context
4972 *
4973 * Cleanup the XPath context data associated to registered functions
4974 */
4975void
4976xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4977 if (ctxt == NULL)
4978 return;
4979
4980 xmlHashFree(ctxt->funcHash, NULL);
4981 ctxt->funcHash = NULL;
4982}
4983
4984/************************************************************************
4985 * *
William M. Brack08171912003-12-29 02:52:11 +00004986 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004987 * *
4988 ************************************************************************/
4989
4990/**
4991 * xmlXPathRegisterVariable:
4992 * @ctxt: the XPath context
4993 * @name: the variable name
4994 * @value: the variable value or NULL
4995 *
4996 * Register a new variable value. If @value is NULL it unregisters
4997 * the variable
4998 *
4999 * Returns 0 in case of success, -1 in case of error
5000 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00005001int
Owen Taylor3473f882001-02-23 17:55:21 +00005002xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5003 xmlXPathObjectPtr value) {
5004 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5005}
5006
5007/**
5008 * xmlXPathRegisterVariableNS:
5009 * @ctxt: the XPath context
5010 * @name: the variable name
5011 * @ns_uri: the variable namespace URI
5012 * @value: the variable value or NULL
5013 *
5014 * Register a new variable value. If @value is NULL it unregisters
5015 * the variable
5016 *
5017 * Returns 0 in case of success, -1 in case of error
5018 */
5019int
5020xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5021 const xmlChar *ns_uri,
5022 xmlXPathObjectPtr value) {
5023 if (ctxt == NULL)
5024 return(-1);
5025 if (name == NULL)
5026 return(-1);
5027
5028 if (ctxt->varHash == NULL)
5029 ctxt->varHash = xmlHashCreate(0);
5030 if (ctxt->varHash == NULL)
5031 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00005032 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005033 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00005034 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00005035 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5036 (void *) value,
5037 (xmlHashDeallocator)xmlXPathFreeObject));
5038}
5039
5040/**
5041 * xmlXPathRegisterVariableLookup:
5042 * @ctxt: the XPath context
5043 * @f: the lookup function
5044 * @data: the lookup data
5045 *
5046 * register an external mechanism to do variable lookup
5047 */
5048void
5049xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5050 xmlXPathVariableLookupFunc f, void *data) {
5051 if (ctxt == NULL)
5052 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00005053 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00005054 ctxt->varLookupData = data;
5055}
5056
5057/**
5058 * xmlXPathVariableLookup:
5059 * @ctxt: the XPath context
5060 * @name: the variable name
5061 *
5062 * Search in the Variable array of the context for the given
5063 * variable value.
5064 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005065 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005066 */
5067xmlXPathObjectPtr
5068xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5069 if (ctxt == NULL)
5070 return(NULL);
5071
5072 if (ctxt->varLookupFunc != NULL) {
5073 xmlXPathObjectPtr ret;
5074
5075 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5076 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00005077 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005078 }
5079 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5080}
5081
5082/**
5083 * xmlXPathVariableLookupNS:
5084 * @ctxt: the XPath context
5085 * @name: the variable name
5086 * @ns_uri: the variable namespace URI
5087 *
5088 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005089 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005090 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005091 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005092 */
5093xmlXPathObjectPtr
5094xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5095 const xmlChar *ns_uri) {
5096 if (ctxt == NULL)
5097 return(NULL);
5098
5099 if (ctxt->varLookupFunc != NULL) {
5100 xmlXPathObjectPtr ret;
5101
5102 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5103 (ctxt->varLookupData, name, ns_uri);
5104 if (ret != NULL) return(ret);
5105 }
5106
5107 if (ctxt->varHash == NULL)
5108 return(NULL);
5109 if (name == NULL)
5110 return(NULL);
5111
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005112 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005113 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005114}
5115
5116/**
5117 * xmlXPathRegisteredVariablesCleanup:
5118 * @ctxt: the XPath context
5119 *
5120 * Cleanup the XPath context data associated to registered variables
5121 */
5122void
5123xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5124 if (ctxt == NULL)
5125 return;
5126
Daniel Veillard76d66f42001-05-16 21:05:17 +00005127 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005128 ctxt->varHash = NULL;
5129}
5130
5131/**
5132 * xmlXPathRegisterNs:
5133 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005134 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005135 * @ns_uri: the namespace name
5136 *
5137 * Register a new namespace. If @ns_uri is NULL it unregisters
5138 * the namespace
5139 *
5140 * Returns 0 in case of success, -1 in case of error
5141 */
5142int
5143xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5144 const xmlChar *ns_uri) {
5145 if (ctxt == NULL)
5146 return(-1);
5147 if (prefix == NULL)
5148 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005149 if (prefix[0] == 0)
5150 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005151
5152 if (ctxt->nsHash == NULL)
5153 ctxt->nsHash = xmlHashCreate(10);
5154 if (ctxt->nsHash == NULL)
5155 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005156 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005157 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005158 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005159 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005160 (xmlHashDeallocator)xmlFree));
5161}
5162
5163/**
5164 * xmlXPathNsLookup:
5165 * @ctxt: the XPath context
5166 * @prefix: the namespace prefix value
5167 *
5168 * Search in the namespace declaration array of the context for the given
5169 * namespace name associated to the given prefix
5170 *
5171 * Returns the value or NULL if not found
5172 */
5173const xmlChar *
5174xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5175 if (ctxt == NULL)
5176 return(NULL);
5177 if (prefix == NULL)
5178 return(NULL);
5179
5180#ifdef XML_XML_NAMESPACE
5181 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5182 return(XML_XML_NAMESPACE);
5183#endif
5184
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005185 if (ctxt->namespaces != NULL) {
5186 int i;
5187
5188 for (i = 0;i < ctxt->nsNr;i++) {
5189 if ((ctxt->namespaces[i] != NULL) &&
5190 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5191 return(ctxt->namespaces[i]->href);
5192 }
5193 }
Owen Taylor3473f882001-02-23 17:55:21 +00005194
5195 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5196}
5197
5198/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005199 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005200 * @ctxt: the XPath context
5201 *
5202 * Cleanup the XPath context data associated to registered variables
5203 */
5204void
5205xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5206 if (ctxt == NULL)
5207 return;
5208
Daniel Veillard42766c02002-08-22 20:52:17 +00005209 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005210 ctxt->nsHash = NULL;
5211}
5212
5213/************************************************************************
5214 * *
5215 * Routines to handle Values *
5216 * *
5217 ************************************************************************/
5218
William M. Brack08171912003-12-29 02:52:11 +00005219/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005220
5221/**
5222 * xmlXPathNewFloat:
5223 * @val: the double value
5224 *
5225 * Create a new xmlXPathObjectPtr of type double and of value @val
5226 *
5227 * Returns the newly created object.
5228 */
5229xmlXPathObjectPtr
5230xmlXPathNewFloat(double val) {
5231 xmlXPathObjectPtr ret;
5232
5233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5234 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005235 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005236 return(NULL);
5237 }
5238 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5239 ret->type = XPATH_NUMBER;
5240 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005241#ifdef XP_DEBUG_OBJ_USAGE
5242 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5243#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005244 return(ret);
5245}
5246
5247/**
5248 * xmlXPathNewBoolean:
5249 * @val: the boolean value
5250 *
5251 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5252 *
5253 * Returns the newly created object.
5254 */
5255xmlXPathObjectPtr
5256xmlXPathNewBoolean(int val) {
5257 xmlXPathObjectPtr ret;
5258
5259 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5260 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005261 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005262 return(NULL);
5263 }
5264 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5265 ret->type = XPATH_BOOLEAN;
5266 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005267#ifdef XP_DEBUG_OBJ_USAGE
5268 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5269#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005270 return(ret);
5271}
5272
5273/**
5274 * xmlXPathNewString:
5275 * @val: the xmlChar * value
5276 *
5277 * Create a new xmlXPathObjectPtr of type string and of value @val
5278 *
5279 * Returns the newly created object.
5280 */
5281xmlXPathObjectPtr
5282xmlXPathNewString(const xmlChar *val) {
5283 xmlXPathObjectPtr ret;
5284
5285 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5286 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005287 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005288 return(NULL);
5289 }
5290 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5291 ret->type = XPATH_STRING;
5292 if (val != NULL)
5293 ret->stringval = xmlStrdup(val);
5294 else
5295 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005296#ifdef XP_DEBUG_OBJ_USAGE
5297 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5298#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005299 return(ret);
5300}
5301
5302/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005303 * xmlXPathWrapString:
5304 * @val: the xmlChar * value
5305 *
5306 * Wraps the @val string into an XPath object.
5307 *
5308 * Returns the newly created object.
5309 */
5310xmlXPathObjectPtr
5311xmlXPathWrapString (xmlChar *val) {
5312 xmlXPathObjectPtr ret;
5313
5314 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5315 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005316 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005317 return(NULL);
5318 }
5319 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5320 ret->type = XPATH_STRING;
5321 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005322#ifdef XP_DEBUG_OBJ_USAGE
5323 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5324#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005325 return(ret);
5326}
5327
5328/**
Owen Taylor3473f882001-02-23 17:55:21 +00005329 * xmlXPathNewCString:
5330 * @val: the char * value
5331 *
5332 * Create a new xmlXPathObjectPtr of type string and of value @val
5333 *
5334 * Returns the newly created object.
5335 */
5336xmlXPathObjectPtr
5337xmlXPathNewCString(const char *val) {
5338 xmlXPathObjectPtr ret;
5339
5340 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5341 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005342 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005343 return(NULL);
5344 }
5345 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5346 ret->type = XPATH_STRING;
5347 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005348#ifdef XP_DEBUG_OBJ_USAGE
5349 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5350#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005351 return(ret);
5352}
5353
5354/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005355 * xmlXPathWrapCString:
5356 * @val: the char * value
5357 *
5358 * Wraps a string into an XPath object.
5359 *
5360 * Returns the newly created object.
5361 */
5362xmlXPathObjectPtr
5363xmlXPathWrapCString (char * val) {
5364 return(xmlXPathWrapString((xmlChar *)(val)));
5365}
5366
5367/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005368 * xmlXPathWrapExternal:
5369 * @val: the user data
5370 *
5371 * Wraps the @val data into an XPath object.
5372 *
5373 * Returns the newly created object.
5374 */
5375xmlXPathObjectPtr
5376xmlXPathWrapExternal (void *val) {
5377 xmlXPathObjectPtr ret;
5378
5379 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5380 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005381 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005382 return(NULL);
5383 }
5384 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5385 ret->type = XPATH_USERS;
5386 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005387#ifdef XP_DEBUG_OBJ_USAGE
5388 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5389#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005390 return(ret);
5391}
5392
5393/**
Owen Taylor3473f882001-02-23 17:55:21 +00005394 * xmlXPathObjectCopy:
5395 * @val: the original object
5396 *
5397 * allocate a new copy of a given object
5398 *
5399 * Returns the newly created object.
5400 */
5401xmlXPathObjectPtr
5402xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5403 xmlXPathObjectPtr ret;
5404
5405 if (val == NULL)
5406 return(NULL);
5407
5408 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5409 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005410 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005411 return(NULL);
5412 }
5413 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005414#ifdef XP_DEBUG_OBJ_USAGE
5415 xmlXPathDebugObjUsageRequested(NULL, val->type);
5416#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005417 switch (val->type) {
5418 case XPATH_BOOLEAN:
5419 case XPATH_NUMBER:
5420 case XPATH_POINT:
5421 case XPATH_RANGE:
5422 break;
5423 case XPATH_STRING:
5424 ret->stringval = xmlStrdup(val->stringval);
5425 break;
5426 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005427#if 0
5428/*
5429 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5430 this previous handling is no longer correct, and can cause some serious
5431 problems (ref. bug 145547)
5432*/
Owen Taylor3473f882001-02-23 17:55:21 +00005433 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005434 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005435 xmlNodePtr cur, tmp;
5436 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005437
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005438 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005439 top = xmlNewDoc(NULL);
5440 top->name = (char *)
5441 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005442 ret->user = top;
5443 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005444 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005445 cur = val->nodesetval->nodeTab[0]->children;
5446 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005447 tmp = xmlDocCopyNode(cur, top, 1);
5448 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005449 cur = cur->next;
5450 }
5451 }
William M. Bracke9449c52004-07-11 14:41:20 +00005452
Daniel Veillard9adc0462003-03-24 18:39:54 +00005453 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005454 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005455 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005456 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005457 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005458#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005459 case XPATH_NODESET:
5460 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005461 /* Do not deallocate the copied tree value */
5462 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005463 break;
5464 case XPATH_LOCATIONSET:
5465#ifdef LIBXML_XPTR_ENABLED
5466 {
5467 xmlLocationSetPtr loc = val->user;
5468 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5469 break;
5470 }
5471#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005472 case XPATH_USERS:
5473 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005474 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005475 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005476 xmlGenericError(xmlGenericErrorContext,
5477 "xmlXPathObjectCopy: unsupported type %d\n",
5478 val->type);
5479 break;
5480 }
5481 return(ret);
5482}
5483
5484/**
5485 * xmlXPathFreeObject:
5486 * @obj: the object to free
5487 *
5488 * Free up an xmlXPathObjectPtr object.
5489 */
5490void
5491xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5492 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005493 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005494 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005495#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005496 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005497 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005498 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005499 } else
5500#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005501 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005502 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005503 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005504 } else {
5505 if (obj->nodesetval != NULL)
5506 xmlXPathFreeNodeSet(obj->nodesetval);
5507 }
Owen Taylor3473f882001-02-23 17:55:21 +00005508#ifdef LIBXML_XPTR_ENABLED
5509 } else if (obj->type == XPATH_LOCATIONSET) {
5510 if (obj->user != NULL)
5511 xmlXPtrFreeLocationSet(obj->user);
5512#endif
5513 } else if (obj->type == XPATH_STRING) {
5514 if (obj->stringval != NULL)
5515 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005516 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005517#ifdef XP_DEBUG_OBJ_USAGE
5518 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5519#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005520 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005521}
Owen Taylor3473f882001-02-23 17:55:21 +00005522
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005523/**
5524 * xmlXPathReleaseObject:
5525 * @obj: the xmlXPathObjectPtr to free or to cache
5526 *
5527 * Depending on the state of the cache this frees the given
5528 * XPath object or stores it in the cache.
5529 */
5530static void
5531xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5532{
5533#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5534 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5535 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5536
5537#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5538
5539 if (obj == NULL)
5540 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005541 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005542 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005543 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005544 xmlXPathContextCachePtr cache =
5545 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005546
5547 switch (obj->type) {
5548 case XPATH_NODESET:
5549 case XPATH_XSLT_TREE:
5550 if (obj->nodesetval != NULL) {
5551 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005552 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005553 * It looks like the @boolval is used for
5554 * evaluation if this an XSLT Result Tree Fragment.
5555 * TODO: Check if this assumption is correct.
5556 */
5557 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5558 xmlXPathFreeValueTree(obj->nodesetval);
5559 obj->nodesetval = NULL;
5560 } else if ((obj->nodesetval->nodeMax <= 40) &&
5561 (XP_CACHE_WANTS(cache->nodesetObjs,
5562 cache->maxNodeset)))
5563 {
5564 XP_CACHE_ADD(cache->nodesetObjs, obj);
5565 goto obj_cached;
5566 } else {
5567 xmlXPathFreeNodeSet(obj->nodesetval);
5568 obj->nodesetval = NULL;
5569 }
5570 }
5571 break;
5572 case XPATH_STRING:
5573 if (obj->stringval != NULL)
5574 xmlFree(obj->stringval);
5575
5576 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5577 XP_CACHE_ADD(cache->stringObjs, obj);
5578 goto obj_cached;
5579 }
5580 break;
5581 case XPATH_BOOLEAN:
5582 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5583 XP_CACHE_ADD(cache->booleanObjs, obj);
5584 goto obj_cached;
5585 }
5586 break;
5587 case XPATH_NUMBER:
5588 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5589 XP_CACHE_ADD(cache->numberObjs, obj);
5590 goto obj_cached;
5591 }
5592 break;
5593#ifdef LIBXML_XPTR_ENABLED
5594 case XPATH_LOCATIONSET:
5595 if (obj->user != NULL) {
5596 xmlXPtrFreeLocationSet(obj->user);
5597 }
5598 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005599#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005600 default:
5601 goto free_obj;
5602 }
5603
5604 /*
5605 * Fallback to adding to the misc-objects slot.
5606 */
5607 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5608 XP_CACHE_ADD(cache->miscObjs, obj);
5609 } else
5610 goto free_obj;
5611
5612obj_cached:
5613
5614#ifdef XP_DEBUG_OBJ_USAGE
5615 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5616#endif
5617
5618 if (obj->nodesetval != NULL) {
5619 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005620
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005621 /*
5622 * TODO: Due to those nasty ns-nodes, we need to traverse
5623 * the list and free the ns-nodes.
5624 * URGENT TODO: Check if it's actually slowing things down.
5625 * Maybe we shouldn't try to preserve the list.
5626 */
5627 if (tmpset->nodeNr > 1) {
5628 int i;
5629 xmlNodePtr node;
5630
5631 for (i = 0; i < tmpset->nodeNr; i++) {
5632 node = tmpset->nodeTab[i];
5633 if ((node != NULL) &&
5634 (node->type == XML_NAMESPACE_DECL))
5635 {
5636 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5637 }
5638 }
5639 } else if (tmpset->nodeNr == 1) {
5640 if ((tmpset->nodeTab[0] != NULL) &&
5641 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5642 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005643 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005644 tmpset->nodeNr = 0;
5645 memset(obj, 0, sizeof(xmlXPathObject));
5646 obj->nodesetval = tmpset;
5647 } else
5648 memset(obj, 0, sizeof(xmlXPathObject));
5649
5650 return;
5651
5652free_obj:
5653 /*
5654 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005655 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005656 if (obj->nodesetval != NULL)
5657 xmlXPathFreeNodeSet(obj->nodesetval);
5658#ifdef XP_DEBUG_OBJ_USAGE
5659 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5660#endif
5661 xmlFree(obj);
5662 }
5663 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005664}
5665
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005666
5667/************************************************************************
5668 * *
5669 * Type Casting Routines *
5670 * *
5671 ************************************************************************/
5672
5673/**
5674 * xmlXPathCastBooleanToString:
5675 * @val: a boolean
5676 *
5677 * Converts a boolean to its string value.
5678 *
5679 * Returns a newly allocated string.
5680 */
5681xmlChar *
5682xmlXPathCastBooleanToString (int val) {
5683 xmlChar *ret;
5684 if (val)
5685 ret = xmlStrdup((const xmlChar *) "true");
5686 else
5687 ret = xmlStrdup((const xmlChar *) "false");
5688 return(ret);
5689}
5690
5691/**
5692 * xmlXPathCastNumberToString:
5693 * @val: a number
5694 *
5695 * Converts a number to its string value.
5696 *
5697 * Returns a newly allocated string.
5698 */
5699xmlChar *
5700xmlXPathCastNumberToString (double val) {
5701 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005702 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005703 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005704 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005705 break;
5706 case -1:
5707 ret = xmlStrdup((const xmlChar *) "-Infinity");
5708 break;
5709 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005710 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005711 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005712 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5713 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005714 } else {
5715 /* could be improved */
5716 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005717 xmlXPathFormatNumber(val, buf, 99);
5718 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005719 ret = xmlStrdup((const xmlChar *) buf);
5720 }
5721 }
5722 return(ret);
5723}
5724
5725/**
5726 * xmlXPathCastNodeToString:
5727 * @node: a node
5728 *
5729 * Converts a node to its string value.
5730 *
5731 * Returns a newly allocated string.
5732 */
5733xmlChar *
5734xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005735xmlChar *ret;
5736 if ((ret = xmlNodeGetContent(node)) == NULL)
5737 ret = xmlStrdup((const xmlChar *) "");
5738 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005739}
5740
5741/**
5742 * xmlXPathCastNodeSetToString:
5743 * @ns: a node-set
5744 *
5745 * Converts a node-set to its string value.
5746 *
5747 * Returns a newly allocated string.
5748 */
5749xmlChar *
5750xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5751 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5752 return(xmlStrdup((const xmlChar *) ""));
5753
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005754 if (ns->nodeNr > 1)
5755 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005756 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5757}
5758
5759/**
5760 * xmlXPathCastToString:
5761 * @val: an XPath object
5762 *
5763 * Converts an existing object to its string() equivalent
5764 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005765 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005766 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005767 */
5768xmlChar *
5769xmlXPathCastToString(xmlXPathObjectPtr val) {
5770 xmlChar *ret = NULL;
5771
5772 if (val == NULL)
5773 return(xmlStrdup((const xmlChar *) ""));
5774 switch (val->type) {
5775 case XPATH_UNDEFINED:
5776#ifdef DEBUG_EXPR
5777 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5778#endif
5779 ret = xmlStrdup((const xmlChar *) "");
5780 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005781 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005782 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005783 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5784 break;
5785 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005786 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005787 case XPATH_BOOLEAN:
5788 ret = xmlXPathCastBooleanToString(val->boolval);
5789 break;
5790 case XPATH_NUMBER: {
5791 ret = xmlXPathCastNumberToString(val->floatval);
5792 break;
5793 }
5794 case XPATH_USERS:
5795 case XPATH_POINT:
5796 case XPATH_RANGE:
5797 case XPATH_LOCATIONSET:
5798 TODO
5799 ret = xmlStrdup((const xmlChar *) "");
5800 break;
5801 }
5802 return(ret);
5803}
5804
5805/**
5806 * xmlXPathConvertString:
5807 * @val: an XPath object
5808 *
5809 * Converts an existing object to its string() equivalent
5810 *
5811 * Returns the new object, the old one is freed (or the operation
5812 * is done directly on @val)
5813 */
5814xmlXPathObjectPtr
5815xmlXPathConvertString(xmlXPathObjectPtr val) {
5816 xmlChar *res = NULL;
5817
5818 if (val == NULL)
5819 return(xmlXPathNewCString(""));
5820
5821 switch (val->type) {
5822 case XPATH_UNDEFINED:
5823#ifdef DEBUG_EXPR
5824 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5825#endif
5826 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005827 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005828 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005829 res = xmlXPathCastNodeSetToString(val->nodesetval);
5830 break;
5831 case XPATH_STRING:
5832 return(val);
5833 case XPATH_BOOLEAN:
5834 res = xmlXPathCastBooleanToString(val->boolval);
5835 break;
5836 case XPATH_NUMBER:
5837 res = xmlXPathCastNumberToString(val->floatval);
5838 break;
5839 case XPATH_USERS:
5840 case XPATH_POINT:
5841 case XPATH_RANGE:
5842 case XPATH_LOCATIONSET:
5843 TODO;
5844 break;
5845 }
5846 xmlXPathFreeObject(val);
5847 if (res == NULL)
5848 return(xmlXPathNewCString(""));
5849 return(xmlXPathWrapString(res));
5850}
5851
5852/**
5853 * xmlXPathCastBooleanToNumber:
5854 * @val: a boolean
5855 *
5856 * Converts a boolean to its number value
5857 *
5858 * Returns the number value
5859 */
5860double
5861xmlXPathCastBooleanToNumber(int val) {
5862 if (val)
5863 return(1.0);
5864 return(0.0);
5865}
5866
5867/**
5868 * xmlXPathCastStringToNumber:
5869 * @val: a string
5870 *
5871 * Converts a string to its number value
5872 *
5873 * Returns the number value
5874 */
5875double
5876xmlXPathCastStringToNumber(const xmlChar * val) {
5877 return(xmlXPathStringEvalNumber(val));
5878}
5879
5880/**
5881 * xmlXPathCastNodeToNumber:
5882 * @node: a node
5883 *
5884 * Converts a node to its number value
5885 *
5886 * Returns the number value
5887 */
5888double
5889xmlXPathCastNodeToNumber (xmlNodePtr node) {
5890 xmlChar *strval;
5891 double ret;
5892
5893 if (node == NULL)
5894 return(xmlXPathNAN);
5895 strval = xmlXPathCastNodeToString(node);
5896 if (strval == NULL)
5897 return(xmlXPathNAN);
5898 ret = xmlXPathCastStringToNumber(strval);
5899 xmlFree(strval);
5900
5901 return(ret);
5902}
5903
5904/**
5905 * xmlXPathCastNodeSetToNumber:
5906 * @ns: a node-set
5907 *
5908 * Converts a node-set to its number value
5909 *
5910 * Returns the number value
5911 */
5912double
5913xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5914 xmlChar *str;
5915 double ret;
5916
5917 if (ns == NULL)
5918 return(xmlXPathNAN);
5919 str = xmlXPathCastNodeSetToString(ns);
5920 ret = xmlXPathCastStringToNumber(str);
5921 xmlFree(str);
5922 return(ret);
5923}
5924
5925/**
5926 * xmlXPathCastToNumber:
5927 * @val: an XPath object
5928 *
5929 * Converts an XPath object to its number value
5930 *
5931 * Returns the number value
5932 */
5933double
5934xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5935 double ret = 0.0;
5936
5937 if (val == NULL)
5938 return(xmlXPathNAN);
5939 switch (val->type) {
5940 case XPATH_UNDEFINED:
5941#ifdef DEGUB_EXPR
5942 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5943#endif
5944 ret = xmlXPathNAN;
5945 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005946 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005947 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005948 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5949 break;
5950 case XPATH_STRING:
5951 ret = xmlXPathCastStringToNumber(val->stringval);
5952 break;
5953 case XPATH_NUMBER:
5954 ret = val->floatval;
5955 break;
5956 case XPATH_BOOLEAN:
5957 ret = xmlXPathCastBooleanToNumber(val->boolval);
5958 break;
5959 case XPATH_USERS:
5960 case XPATH_POINT:
5961 case XPATH_RANGE:
5962 case XPATH_LOCATIONSET:
5963 TODO;
5964 ret = xmlXPathNAN;
5965 break;
5966 }
5967 return(ret);
5968}
5969
5970/**
5971 * xmlXPathConvertNumber:
5972 * @val: an XPath object
5973 *
5974 * Converts an existing object to its number() equivalent
5975 *
5976 * Returns the new object, the old one is freed (or the operation
5977 * is done directly on @val)
5978 */
5979xmlXPathObjectPtr
5980xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5981 xmlXPathObjectPtr ret;
5982
5983 if (val == NULL)
5984 return(xmlXPathNewFloat(0.0));
5985 if (val->type == XPATH_NUMBER)
5986 return(val);
5987 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5988 xmlXPathFreeObject(val);
5989 return(ret);
5990}
5991
5992/**
5993 * xmlXPathCastNumberToBoolean:
5994 * @val: a number
5995 *
5996 * Converts a number to its boolean value
5997 *
5998 * Returns the boolean value
5999 */
6000int
6001xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00006002 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006003 return(0);
6004 return(1);
6005}
6006
6007/**
6008 * xmlXPathCastStringToBoolean:
6009 * @val: a string
6010 *
6011 * Converts a string to its boolean value
6012 *
6013 * Returns the boolean value
6014 */
6015int
6016xmlXPathCastStringToBoolean (const xmlChar *val) {
6017 if ((val == NULL) || (xmlStrlen(val) == 0))
6018 return(0);
6019 return(1);
6020}
6021
6022/**
6023 * xmlXPathCastNodeSetToBoolean:
6024 * @ns: a node-set
6025 *
6026 * Converts a node-set to its boolean value
6027 *
6028 * Returns the boolean value
6029 */
6030int
6031xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6032 if ((ns == NULL) || (ns->nodeNr == 0))
6033 return(0);
6034 return(1);
6035}
6036
6037/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006038 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006039 * @val: an XPath object
6040 *
6041 * Converts an XPath object to its boolean value
6042 *
6043 * Returns the boolean value
6044 */
6045int
6046xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6047 int ret = 0;
6048
6049 if (val == NULL)
6050 return(0);
6051 switch (val->type) {
6052 case XPATH_UNDEFINED:
6053#ifdef DEBUG_EXPR
6054 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6055#endif
6056 ret = 0;
6057 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006058 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00006059 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006060 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6061 break;
6062 case XPATH_STRING:
6063 ret = xmlXPathCastStringToBoolean(val->stringval);
6064 break;
6065 case XPATH_NUMBER:
6066 ret = xmlXPathCastNumberToBoolean(val->floatval);
6067 break;
6068 case XPATH_BOOLEAN:
6069 ret = val->boolval;
6070 break;
6071 case XPATH_USERS:
6072 case XPATH_POINT:
6073 case XPATH_RANGE:
6074 case XPATH_LOCATIONSET:
6075 TODO;
6076 ret = 0;
6077 break;
6078 }
6079 return(ret);
6080}
6081
6082
6083/**
6084 * xmlXPathConvertBoolean:
6085 * @val: an XPath object
6086 *
6087 * Converts an existing object to its boolean() equivalent
6088 *
6089 * Returns the new object, the old one is freed (or the operation
6090 * is done directly on @val)
6091 */
6092xmlXPathObjectPtr
6093xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6094 xmlXPathObjectPtr ret;
6095
6096 if (val == NULL)
6097 return(xmlXPathNewBoolean(0));
6098 if (val->type == XPATH_BOOLEAN)
6099 return(val);
6100 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6101 xmlXPathFreeObject(val);
6102 return(ret);
6103}
6104
Owen Taylor3473f882001-02-23 17:55:21 +00006105/************************************************************************
6106 * *
6107 * Routines to handle XPath contexts *
6108 * *
6109 ************************************************************************/
6110
6111/**
6112 * xmlXPathNewContext:
6113 * @doc: the XML document
6114 *
6115 * Create a new xmlXPathContext
6116 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006117 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006118 */
6119xmlXPathContextPtr
6120xmlXPathNewContext(xmlDocPtr doc) {
6121 xmlXPathContextPtr ret;
6122
6123 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6124 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006125 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006126 return(NULL);
6127 }
6128 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6129 ret->doc = doc;
6130 ret->node = NULL;
6131
6132 ret->varHash = NULL;
6133
6134 ret->nb_types = 0;
6135 ret->max_types = 0;
6136 ret->types = NULL;
6137
6138 ret->funcHash = xmlHashCreate(0);
6139
6140 ret->nb_axis = 0;
6141 ret->max_axis = 0;
6142 ret->axis = NULL;
6143
6144 ret->nsHash = NULL;
6145 ret->user = NULL;
6146
6147 ret->contextSize = -1;
6148 ret->proximityPosition = -1;
6149
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006150#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006151 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006152 xmlXPathFreeContext(ret);
6153 return(NULL);
6154 }
6155#endif
6156
Daniel Veillard45490ae2008-07-29 09:13:19 +00006157 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006158
Owen Taylor3473f882001-02-23 17:55:21 +00006159 return(ret);
6160}
6161
6162/**
6163 * xmlXPathFreeContext:
6164 * @ctxt: the context to free
6165 *
6166 * Free up an xmlXPathContext
6167 */
6168void
6169xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006170 if (ctxt == NULL) return;
6171
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006172 if (ctxt->cache != NULL)
6173 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006174 xmlXPathRegisteredNsCleanup(ctxt);
6175 xmlXPathRegisteredFuncsCleanup(ctxt);
6176 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006177 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006178 xmlFree(ctxt);
6179}
6180
6181/************************************************************************
6182 * *
6183 * Routines to handle XPath parser contexts *
6184 * *
6185 ************************************************************************/
6186
6187#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006188 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006189 __xmlRaiseError(NULL, NULL, NULL, \
6190 NULL, NULL, XML_FROM_XPATH, \
6191 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6192 __FILE__, __LINE__, \
6193 NULL, NULL, NULL, 0, 0, \
6194 "NULL context pointer\n"); \
6195 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006196 } \
6197
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006198#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006199 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006200 __xmlRaiseError(NULL, NULL, NULL, \
6201 NULL, NULL, XML_FROM_XPATH, \
6202 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6203 __FILE__, __LINE__, \
6204 NULL, NULL, NULL, 0, 0, \
6205 "NULL context pointer\n"); \
6206 return(-1); \
6207 } \
6208
Owen Taylor3473f882001-02-23 17:55:21 +00006209
6210#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006211 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006212 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006213 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006214 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006215 }
Owen Taylor3473f882001-02-23 17:55:21 +00006216
6217
6218/**
6219 * xmlXPathNewParserContext:
6220 * @str: the XPath expression
6221 * @ctxt: the XPath context
6222 *
6223 * Create a new xmlXPathParserContext
6224 *
6225 * Returns the xmlXPathParserContext just allocated.
6226 */
6227xmlXPathParserContextPtr
6228xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6229 xmlXPathParserContextPtr ret;
6230
6231 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6232 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006233 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006234 return(NULL);
6235 }
6236 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6237 ret->cur = ret->base = str;
6238 ret->context = ctxt;
6239
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006240 ret->comp = xmlXPathNewCompExpr();
6241 if (ret->comp == NULL) {
6242 xmlFree(ret->valueTab);
6243 xmlFree(ret);
6244 return(NULL);
6245 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006246 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6247 ret->comp->dict = ctxt->dict;
6248 xmlDictReference(ret->comp->dict);
6249 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006250
6251 return(ret);
6252}
6253
6254/**
6255 * xmlXPathCompParserContext:
6256 * @comp: the XPath compiled expression
6257 * @ctxt: the XPath context
6258 *
6259 * Create a new xmlXPathParserContext when processing a compiled expression
6260 *
6261 * Returns the xmlXPathParserContext just allocated.
6262 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006263static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006264xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6265 xmlXPathParserContextPtr ret;
6266
6267 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6268 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006269 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006270 return(NULL);
6271 }
6272 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6273
Owen Taylor3473f882001-02-23 17:55:21 +00006274 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006275 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006276 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006277 if (ret->valueTab == NULL) {
6278 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006279 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006280 return(NULL);
6281 }
Owen Taylor3473f882001-02-23 17:55:21 +00006282 ret->valueNr = 0;
6283 ret->valueMax = 10;
6284 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006285 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006286
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006287 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006288 ret->comp = comp;
6289
Owen Taylor3473f882001-02-23 17:55:21 +00006290 return(ret);
6291}
6292
6293/**
6294 * xmlXPathFreeParserContext:
6295 * @ctxt: the context to free
6296 *
6297 * Free up an xmlXPathParserContext
6298 */
6299void
6300xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006301 int i;
6302
Owen Taylor3473f882001-02-23 17:55:21 +00006303 if (ctxt->valueTab != NULL) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006304 for (i = 0; i < ctxt->valueNr; i++) {
6305 if (ctxt->context)
6306 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6307 else
6308 xmlXPathFreeObject(ctxt->valueTab[i]);
6309 }
Owen Taylor3473f882001-02-23 17:55:21 +00006310 xmlFree(ctxt->valueTab);
6311 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006312 if (ctxt->comp != NULL) {
6313#ifdef XPATH_STREAMING
6314 if (ctxt->comp->stream != NULL) {
6315 xmlFreePatternList(ctxt->comp->stream);
6316 ctxt->comp->stream = NULL;
6317 }
6318#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006319 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006320 }
Owen Taylor3473f882001-02-23 17:55:21 +00006321 xmlFree(ctxt);
6322}
6323
6324/************************************************************************
6325 * *
6326 * The implicit core function library *
6327 * *
6328 ************************************************************************/
6329
Owen Taylor3473f882001-02-23 17:55:21 +00006330/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006331 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006332 * @node: a node pointer
6333 *
6334 * Function computing the beginning of the string value of the node,
6335 * used to speed up comparisons
6336 *
6337 * Returns an int usable as a hash
6338 */
6339static unsigned int
6340xmlXPathNodeValHash(xmlNodePtr node) {
6341 int len = 2;
6342 const xmlChar * string = NULL;
6343 xmlNodePtr tmp = NULL;
6344 unsigned int ret = 0;
6345
6346 if (node == NULL)
6347 return(0);
6348
Daniel Veillard9adc0462003-03-24 18:39:54 +00006349 if (node->type == XML_DOCUMENT_NODE) {
6350 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6351 if (tmp == NULL)
6352 node = node->children;
6353 else
6354 node = tmp;
6355
6356 if (node == NULL)
6357 return(0);
6358 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006359
6360 switch (node->type) {
6361 case XML_COMMENT_NODE:
6362 case XML_PI_NODE:
6363 case XML_CDATA_SECTION_NODE:
6364 case XML_TEXT_NODE:
6365 string = node->content;
6366 if (string == NULL)
6367 return(0);
6368 if (string[0] == 0)
6369 return(0);
6370 return(((unsigned int) string[0]) +
6371 (((unsigned int) string[1]) << 8));
6372 case XML_NAMESPACE_DECL:
6373 string = ((xmlNsPtr)node)->href;
6374 if (string == NULL)
6375 return(0);
6376 if (string[0] == 0)
6377 return(0);
6378 return(((unsigned int) string[0]) +
6379 (((unsigned int) string[1]) << 8));
6380 case XML_ATTRIBUTE_NODE:
6381 tmp = ((xmlAttrPtr) node)->children;
6382 break;
6383 case XML_ELEMENT_NODE:
6384 tmp = node->children;
6385 break;
6386 default:
6387 return(0);
6388 }
6389 while (tmp != NULL) {
6390 switch (tmp->type) {
6391 case XML_COMMENT_NODE:
6392 case XML_PI_NODE:
6393 case XML_CDATA_SECTION_NODE:
6394 case XML_TEXT_NODE:
6395 string = tmp->content;
6396 break;
6397 case XML_NAMESPACE_DECL:
6398 string = ((xmlNsPtr)tmp)->href;
6399 break;
6400 default:
6401 break;
6402 }
6403 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006404 if (len == 1) {
6405 return(ret + (((unsigned int) string[0]) << 8));
6406 }
6407 if (string[1] == 0) {
6408 len = 1;
6409 ret = (unsigned int) string[0];
6410 } else {
6411 return(((unsigned int) string[0]) +
6412 (((unsigned int) string[1]) << 8));
6413 }
6414 }
6415 /*
6416 * Skip to next node
6417 */
6418 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6419 if (tmp->children->type != XML_ENTITY_DECL) {
6420 tmp = tmp->children;
6421 continue;
6422 }
6423 }
6424 if (tmp == node)
6425 break;
6426
6427 if (tmp->next != NULL) {
6428 tmp = tmp->next;
6429 continue;
6430 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006431
Daniel Veillardf06307e2001-07-03 10:35:50 +00006432 do {
6433 tmp = tmp->parent;
6434 if (tmp == NULL)
6435 break;
6436 if (tmp == node) {
6437 tmp = NULL;
6438 break;
6439 }
6440 if (tmp->next != NULL) {
6441 tmp = tmp->next;
6442 break;
6443 }
6444 } while (tmp != NULL);
6445 }
6446 return(ret);
6447}
6448
6449/**
6450 * xmlXPathStringHash:
6451 * @string: a string
6452 *
6453 * Function computing the beginning of the string value of the node,
6454 * used to speed up comparisons
6455 *
6456 * Returns an int usable as a hash
6457 */
6458static unsigned int
6459xmlXPathStringHash(const xmlChar * string) {
6460 if (string == NULL)
6461 return((unsigned int) 0);
6462 if (string[0] == 0)
6463 return(0);
6464 return(((unsigned int) string[0]) +
6465 (((unsigned int) string[1]) << 8));
6466}
6467
6468/**
Owen Taylor3473f882001-02-23 17:55:21 +00006469 * xmlXPathCompareNodeSetFloat:
6470 * @ctxt: the XPath Parser context
6471 * @inf: less than (1) or greater than (0)
6472 * @strict: is the comparison strict
6473 * @arg: the node set
6474 * @f: the value
6475 *
6476 * Implement the compare operation between a nodeset and a number
6477 * @ns < @val (1, 1, ...
6478 * @ns <= @val (1, 0, ...
6479 * @ns > @val (0, 1, ...
6480 * @ns >= @val (0, 0, ...
6481 *
6482 * If one object to be compared is a node-set and the other is a number,
6483 * then the comparison will be true if and only if there is a node in the
6484 * node-set such that the result of performing the comparison on the number
6485 * to be compared and on the result of converting the string-value of that
6486 * node to a number using the number function is true.
6487 *
6488 * Returns 0 or 1 depending on the results of the test.
6489 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006490static int
Owen Taylor3473f882001-02-23 17:55:21 +00006491xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6492 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6493 int i, ret = 0;
6494 xmlNodeSetPtr ns;
6495 xmlChar *str2;
6496
6497 if ((f == NULL) || (arg == NULL) ||
6498 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006499 xmlXPathReleaseObject(ctxt->context, arg);
6500 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006501 return(0);
6502 }
6503 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006504 if (ns != NULL) {
6505 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006506 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006507 if (str2 != NULL) {
6508 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006509 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006510 xmlFree(str2);
6511 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006512 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006513 ret = xmlXPathCompareValues(ctxt, inf, strict);
6514 if (ret)
6515 break;
6516 }
6517 }
Owen Taylor3473f882001-02-23 17:55:21 +00006518 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006519 xmlXPathReleaseObject(ctxt->context, arg);
6520 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006521 return(ret);
6522}
6523
6524/**
6525 * xmlXPathCompareNodeSetString:
6526 * @ctxt: the XPath Parser context
6527 * @inf: less than (1) or greater than (0)
6528 * @strict: is the comparison strict
6529 * @arg: the node set
6530 * @s: the value
6531 *
6532 * Implement the compare operation between a nodeset and a string
6533 * @ns < @val (1, 1, ...
6534 * @ns <= @val (1, 0, ...
6535 * @ns > @val (0, 1, ...
6536 * @ns >= @val (0, 0, ...
6537 *
6538 * If one object to be compared is a node-set and the other is a string,
6539 * then the comparison will be true if and only if there is a node in
6540 * the node-set such that the result of performing the comparison on the
6541 * string-value of the node and the other string is true.
6542 *
6543 * Returns 0 or 1 depending on the results of the test.
6544 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006545static int
Owen Taylor3473f882001-02-23 17:55:21 +00006546xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6547 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6548 int i, ret = 0;
6549 xmlNodeSetPtr ns;
6550 xmlChar *str2;
6551
6552 if ((s == NULL) || (arg == NULL) ||
6553 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006554 xmlXPathReleaseObject(ctxt->context, arg);
6555 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006556 return(0);
6557 }
6558 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006559 if (ns != NULL) {
6560 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006561 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006562 if (str2 != NULL) {
6563 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006564 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006565 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006566 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006567 ret = xmlXPathCompareValues(ctxt, inf, strict);
6568 if (ret)
6569 break;
6570 }
6571 }
Owen Taylor3473f882001-02-23 17:55:21 +00006572 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006573 xmlXPathReleaseObject(ctxt->context, arg);
6574 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006575 return(ret);
6576}
6577
6578/**
6579 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006580 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006581 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006582 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006583 * @arg2: the second node set object
6584 *
6585 * Implement the compare operation on nodesets:
6586 *
6587 * If both objects to be compared are node-sets, then the comparison
6588 * will be true if and only if there is a node in the first node-set
6589 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006590 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006591 * ....
6592 * When neither object to be compared is a node-set and the operator
6593 * is <=, <, >= or >, then the objects are compared by converting both
6594 * objects to numbers and comparing the numbers according to IEEE 754.
6595 * ....
6596 * The number function converts its argument to a number as follows:
6597 * - a string that consists of optional whitespace followed by an
6598 * optional minus sign followed by a Number followed by whitespace
6599 * is converted to the IEEE 754 number that is nearest (according
6600 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6601 * represented by the string; any other string is converted to NaN
6602 *
6603 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006604 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006605 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006606static int
6607xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006608 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6609 int i, j, init = 0;
6610 double val1;
6611 double *values2;
6612 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006613 xmlNodeSetPtr ns1;
6614 xmlNodeSetPtr ns2;
6615
6616 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006617 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6618 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006619 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006620 }
Owen Taylor3473f882001-02-23 17:55:21 +00006621 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006622 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6623 xmlXPathFreeObject(arg1);
6624 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006625 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006626 }
Owen Taylor3473f882001-02-23 17:55:21 +00006627
6628 ns1 = arg1->nodesetval;
6629 ns2 = arg2->nodesetval;
6630
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006631 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006632 xmlXPathFreeObject(arg1);
6633 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006634 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006635 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006636 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006637 xmlXPathFreeObject(arg1);
6638 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006639 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006640 }
Owen Taylor3473f882001-02-23 17:55:21 +00006641
6642 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6643 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006644 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006645 xmlXPathFreeObject(arg1);
6646 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006647 return(0);
6648 }
6649 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006650 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006651 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006652 continue;
6653 for (j = 0;j < ns2->nodeNr;j++) {
6654 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006655 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006656 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006657 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006658 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006659 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006660 ret = (val1 < values2[j]);
6661 else if (inf && !strict)
6662 ret = (val1 <= values2[j]);
6663 else if (!inf && strict)
6664 ret = (val1 > values2[j]);
6665 else if (!inf && !strict)
6666 ret = (val1 >= values2[j]);
6667 if (ret)
6668 break;
6669 }
6670 if (ret)
6671 break;
6672 init = 1;
6673 }
6674 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006675 xmlXPathFreeObject(arg1);
6676 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006677 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006678}
6679
6680/**
6681 * xmlXPathCompareNodeSetValue:
6682 * @ctxt: the XPath Parser context
6683 * @inf: less than (1) or greater than (0)
6684 * @strict: is the comparison strict
6685 * @arg: the node set
6686 * @val: the value
6687 *
6688 * Implement the compare operation between a nodeset and a value
6689 * @ns < @val (1, 1, ...
6690 * @ns <= @val (1, 0, ...
6691 * @ns > @val (0, 1, ...
6692 * @ns >= @val (0, 0, ...
6693 *
6694 * If one object to be compared is a node-set and the other is a boolean,
6695 * then the comparison will be true if and only if the result of performing
6696 * the comparison on the boolean and on the result of converting
6697 * the node-set to a boolean using the boolean function is true.
6698 *
6699 * Returns 0 or 1 depending on the results of the test.
6700 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006701static int
Owen Taylor3473f882001-02-23 17:55:21 +00006702xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6703 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6704 if ((val == NULL) || (arg == NULL) ||
6705 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6706 return(0);
6707
6708 switch(val->type) {
6709 case XPATH_NUMBER:
6710 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6711 case XPATH_NODESET:
6712 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006713 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006714 case XPATH_STRING:
6715 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6716 case XPATH_BOOLEAN:
6717 valuePush(ctxt, arg);
6718 xmlXPathBooleanFunction(ctxt, 1);
6719 valuePush(ctxt, val);
6720 return(xmlXPathCompareValues(ctxt, inf, strict));
6721 default:
Nick Wellnhofercf60dbe2017-05-25 16:20:56 +02006722 xmlGenericError(xmlGenericErrorContext,
6723 "xmlXPathCompareNodeSetValue: Can't compare node set "
6724 "and object of type %d\n",
6725 val->type);
6726 xmlXPathReleaseObject(ctxt->context, arg);
6727 xmlXPathReleaseObject(ctxt->context, val);
6728 XP_ERROR0(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006729 }
6730 return(0);
6731}
6732
6733/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006734 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006735 * @arg: the nodeset object argument
6736 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006737 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006738 *
6739 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6740 * If one object to be compared is a node-set and the other is a string,
6741 * then the comparison will be true if and only if there is a node in
6742 * the node-set such that the result of performing the comparison on the
6743 * string-value of the node and the other string is true.
6744 *
6745 * Returns 0 or 1 depending on the results of the test.
6746 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006747static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006748xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006749{
Owen Taylor3473f882001-02-23 17:55:21 +00006750 int i;
6751 xmlNodeSetPtr ns;
6752 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006753 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006754
6755 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006756 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6757 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006758 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006759 /*
6760 * A NULL nodeset compared with a string is always false
6761 * (since there is no node equal, and no node not equal)
6762 */
6763 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006764 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006765 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006766 for (i = 0; i < ns->nodeNr; i++) {
6767 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6768 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6769 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6770 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006771 if (neq)
6772 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006773 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006774 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6775 if (neq)
6776 continue;
6777 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006778 } else if (neq) {
6779 if (str2 != NULL)
6780 xmlFree(str2);
6781 return (1);
6782 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006783 if (str2 != NULL)
6784 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006785 } else if (neq)
6786 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006787 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006788 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006789}
6790
6791/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006792 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006793 * @arg: the nodeset object argument
6794 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006795 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006796 *
6797 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6798 * If one object to be compared is a node-set and the other is a number,
6799 * then the comparison will be true if and only if there is a node in
6800 * the node-set such that the result of performing the comparison on the
6801 * number to be compared and on the result of converting the string-value
6802 * of that node to a number using the number function is true.
6803 *
6804 * Returns 0 or 1 depending on the results of the test.
6805 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006806static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006807xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6808 xmlXPathObjectPtr arg, double f, int neq) {
6809 int i, ret=0;
6810 xmlNodeSetPtr ns;
6811 xmlChar *str2;
6812 xmlXPathObjectPtr val;
6813 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006814
6815 if ((arg == NULL) ||
6816 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6817 return(0);
6818
William M. Brack0c022ad2002-07-12 00:56:01 +00006819 ns = arg->nodesetval;
6820 if (ns != NULL) {
6821 for (i=0;i<ns->nodeNr;i++) {
6822 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6823 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006824 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006825 xmlFree(str2);
6826 xmlXPathNumberFunction(ctxt, 1);
6827 val = valuePop(ctxt);
6828 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006829 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006830 if (!xmlXPathIsNaN(v)) {
6831 if ((!neq) && (v==f)) {
6832 ret = 1;
6833 break;
6834 } else if ((neq) && (v!=f)) {
6835 ret = 1;
6836 break;
6837 }
William M. Brack32f0f712005-07-14 07:00:33 +00006838 } else { /* NaN is unequal to any value */
6839 if (neq)
6840 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006841 }
6842 }
6843 }
6844 }
6845
6846 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006847}
6848
6849
6850/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006851 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006852 * @arg1: first nodeset object argument
6853 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006854 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006855 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006856 * Implement the equal / not equal operation on XPath nodesets:
6857 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006858 * If both objects to be compared are node-sets, then the comparison
6859 * will be true if and only if there is a node in the first node-set and
6860 * a node in the second node-set such that the result of performing the
6861 * comparison on the string-values of the two nodes is true.
6862 *
6863 * (needless to say, this is a costly operation)
6864 *
6865 * Returns 0 or 1 depending on the results of the test.
6866 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006867static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006868xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006869 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006870 unsigned int *hashs1;
6871 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006872 xmlChar **values1;
6873 xmlChar **values2;
6874 int ret = 0;
6875 xmlNodeSetPtr ns1;
6876 xmlNodeSetPtr ns2;
6877
6878 if ((arg1 == NULL) ||
6879 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6880 return(0);
6881 if ((arg2 == NULL) ||
6882 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6883 return(0);
6884
6885 ns1 = arg1->nodesetval;
6886 ns2 = arg2->nodesetval;
6887
Daniel Veillard911f49a2001-04-07 15:39:35 +00006888 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006889 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006890 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006891 return(0);
6892
6893 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006894 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006895 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006896 if (neq == 0)
6897 for (i = 0;i < ns1->nodeNr;i++)
6898 for (j = 0;j < ns2->nodeNr;j++)
6899 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6900 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006901
6902 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006903 if (values1 == NULL) {
6904 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006905 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006906 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006907 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6908 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006909 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006910 xmlFree(values1);
6911 return(0);
6912 }
Owen Taylor3473f882001-02-23 17:55:21 +00006913 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6914 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6915 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006916 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006917 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006918 xmlFree(values1);
6919 return(0);
6920 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006921 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6922 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006923 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006924 xmlFree(hashs1);
6925 xmlFree(values1);
6926 xmlFree(values2);
6927 return(0);
6928 }
Owen Taylor3473f882001-02-23 17:55:21 +00006929 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6930 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006931 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006932 for (j = 0;j < ns2->nodeNr;j++) {
6933 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006934 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006935 if (hashs1[i] != hashs2[j]) {
6936 if (neq) {
6937 ret = 1;
6938 break;
6939 }
6940 }
6941 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006942 if (values1[i] == NULL)
6943 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6944 if (values2[j] == NULL)
6945 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006946 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006947 if (ret)
6948 break;
6949 }
Owen Taylor3473f882001-02-23 17:55:21 +00006950 }
6951 if (ret)
6952 break;
6953 }
6954 for (i = 0;i < ns1->nodeNr;i++)
6955 if (values1[i] != NULL)
6956 xmlFree(values1[i]);
6957 for (j = 0;j < ns2->nodeNr;j++)
6958 if (values2[j] != NULL)
6959 xmlFree(values2[j]);
6960 xmlFree(values1);
6961 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006962 xmlFree(hashs1);
6963 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006964 return(ret);
6965}
6966
William M. Brack0c022ad2002-07-12 00:56:01 +00006967static int
6968xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6969 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006970 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006971 /*
6972 *At this point we are assured neither arg1 nor arg2
6973 *is a nodeset, so we can just pick the appropriate routine.
6974 */
Owen Taylor3473f882001-02-23 17:55:21 +00006975 switch (arg1->type) {
6976 case XPATH_UNDEFINED:
6977#ifdef DEBUG_EXPR
6978 xmlGenericError(xmlGenericErrorContext,
6979 "Equal: undefined\n");
6980#endif
6981 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006982 case XPATH_BOOLEAN:
6983 switch (arg2->type) {
6984 case XPATH_UNDEFINED:
6985#ifdef DEBUG_EXPR
6986 xmlGenericError(xmlGenericErrorContext,
6987 "Equal: undefined\n");
6988#endif
6989 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006990 case XPATH_BOOLEAN:
6991#ifdef DEBUG_EXPR
6992 xmlGenericError(xmlGenericErrorContext,
6993 "Equal: %d boolean %d \n",
6994 arg1->boolval, arg2->boolval);
6995#endif
6996 ret = (arg1->boolval == arg2->boolval);
6997 break;
6998 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006999 ret = (arg1->boolval ==
7000 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007001 break;
7002 case XPATH_STRING:
7003 if ((arg2->stringval == NULL) ||
7004 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007005 else
Owen Taylor3473f882001-02-23 17:55:21 +00007006 ret = 1;
7007 ret = (arg1->boolval == ret);
7008 break;
7009 case XPATH_USERS:
7010 case XPATH_POINT:
7011 case XPATH_RANGE:
7012 case XPATH_LOCATIONSET:
7013 TODO
7014 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007015 case XPATH_NODESET:
7016 case XPATH_XSLT_TREE:
7017 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007018 }
7019 break;
7020 case XPATH_NUMBER:
7021 switch (arg2->type) {
7022 case XPATH_UNDEFINED:
7023#ifdef DEBUG_EXPR
7024 xmlGenericError(xmlGenericErrorContext,
7025 "Equal: undefined\n");
7026#endif
7027 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007028 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00007029 ret = (arg2->boolval==
7030 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007031 break;
7032 case XPATH_STRING:
7033 valuePush(ctxt, arg2);
7034 xmlXPathNumberFunction(ctxt, 1);
7035 arg2 = valuePop(ctxt);
7036 /* no break on purpose */
7037 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007038 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007039 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007040 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007041 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007042 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7043 if (xmlXPathIsInf(arg2->floatval) == 1)
7044 ret = 1;
7045 else
7046 ret = 0;
7047 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7048 if (xmlXPathIsInf(arg2->floatval) == -1)
7049 ret = 1;
7050 else
7051 ret = 0;
7052 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7053 if (xmlXPathIsInf(arg1->floatval) == 1)
7054 ret = 1;
7055 else
7056 ret = 0;
7057 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7058 if (xmlXPathIsInf(arg1->floatval) == -1)
7059 ret = 1;
7060 else
7061 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007062 } else {
7063 ret = (arg1->floatval == arg2->floatval);
7064 }
Owen Taylor3473f882001-02-23 17:55:21 +00007065 break;
7066 case XPATH_USERS:
7067 case XPATH_POINT:
7068 case XPATH_RANGE:
7069 case XPATH_LOCATIONSET:
7070 TODO
7071 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007072 case XPATH_NODESET:
7073 case XPATH_XSLT_TREE:
7074 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007075 }
7076 break;
7077 case XPATH_STRING:
7078 switch (arg2->type) {
7079 case XPATH_UNDEFINED:
7080#ifdef DEBUG_EXPR
7081 xmlGenericError(xmlGenericErrorContext,
7082 "Equal: undefined\n");
7083#endif
7084 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007085 case XPATH_BOOLEAN:
7086 if ((arg1->stringval == NULL) ||
7087 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007088 else
Owen Taylor3473f882001-02-23 17:55:21 +00007089 ret = 1;
7090 ret = (arg2->boolval == ret);
7091 break;
7092 case XPATH_STRING:
7093 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7094 break;
7095 case XPATH_NUMBER:
7096 valuePush(ctxt, arg1);
7097 xmlXPathNumberFunction(ctxt, 1);
7098 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007099 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007100 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007101 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007102 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007103 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7104 if (xmlXPathIsInf(arg2->floatval) == 1)
7105 ret = 1;
7106 else
7107 ret = 0;
7108 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7109 if (xmlXPathIsInf(arg2->floatval) == -1)
7110 ret = 1;
7111 else
7112 ret = 0;
7113 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7114 if (xmlXPathIsInf(arg1->floatval) == 1)
7115 ret = 1;
7116 else
7117 ret = 0;
7118 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7119 if (xmlXPathIsInf(arg1->floatval) == -1)
7120 ret = 1;
7121 else
7122 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007123 } else {
7124 ret = (arg1->floatval == arg2->floatval);
7125 }
Owen Taylor3473f882001-02-23 17:55:21 +00007126 break;
7127 case XPATH_USERS:
7128 case XPATH_POINT:
7129 case XPATH_RANGE:
7130 case XPATH_LOCATIONSET:
7131 TODO
7132 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007133 case XPATH_NODESET:
7134 case XPATH_XSLT_TREE:
7135 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007136 }
7137 break;
7138 case XPATH_USERS:
7139 case XPATH_POINT:
7140 case XPATH_RANGE:
7141 case XPATH_LOCATIONSET:
7142 TODO
7143 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007144 case XPATH_NODESET:
7145 case XPATH_XSLT_TREE:
7146 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007147 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007148 xmlXPathReleaseObject(ctxt->context, arg1);
7149 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007150 return(ret);
7151}
7152
William M. Brack0c022ad2002-07-12 00:56:01 +00007153/**
7154 * xmlXPathEqualValues:
7155 * @ctxt: the XPath Parser context
7156 *
7157 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7158 *
7159 * Returns 0 or 1 depending on the results of the test.
7160 */
7161int
7162xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7163 xmlXPathObjectPtr arg1, arg2, argtmp;
7164 int ret = 0;
7165
Daniel Veillard6128c012004-11-08 17:16:15 +00007166 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007167 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007168 arg1 = valuePop(ctxt);
7169 if ((arg1 == NULL) || (arg2 == NULL)) {
7170 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007171 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007172 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007173 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007174 XP_ERROR0(XPATH_INVALID_OPERAND);
7175 }
7176
7177 if (arg1 == arg2) {
7178#ifdef DEBUG_EXPR
7179 xmlGenericError(xmlGenericErrorContext,
7180 "Equal: by pointer\n");
7181#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007182 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007183 return(1);
7184 }
7185
7186 /*
7187 *If either argument is a nodeset, it's a 'special case'
7188 */
7189 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7190 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7191 /*
7192 *Hack it to assure arg1 is the nodeset
7193 */
7194 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7195 argtmp = arg2;
7196 arg2 = arg1;
7197 arg1 = argtmp;
7198 }
7199 switch (arg2->type) {
7200 case XPATH_UNDEFINED:
7201#ifdef DEBUG_EXPR
7202 xmlGenericError(xmlGenericErrorContext,
7203 "Equal: undefined\n");
7204#endif
7205 break;
7206 case XPATH_NODESET:
7207 case XPATH_XSLT_TREE:
7208 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7209 break;
7210 case XPATH_BOOLEAN:
7211 if ((arg1->nodesetval == NULL) ||
7212 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007213 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007214 ret = 1;
7215 ret = (ret == arg2->boolval);
7216 break;
7217 case XPATH_NUMBER:
7218 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7219 break;
7220 case XPATH_STRING:
7221 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7222 break;
7223 case XPATH_USERS:
7224 case XPATH_POINT:
7225 case XPATH_RANGE:
7226 case XPATH_LOCATIONSET:
7227 TODO
7228 break;
7229 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007230 xmlXPathReleaseObject(ctxt->context, arg1);
7231 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007232 return(ret);
7233 }
7234
7235 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7236}
7237
7238/**
7239 * xmlXPathNotEqualValues:
7240 * @ctxt: the XPath Parser context
7241 *
7242 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7243 *
7244 * Returns 0 or 1 depending on the results of the test.
7245 */
7246int
7247xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7248 xmlXPathObjectPtr arg1, arg2, argtmp;
7249 int ret = 0;
7250
Daniel Veillard6128c012004-11-08 17:16:15 +00007251 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007252 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007253 arg1 = valuePop(ctxt);
7254 if ((arg1 == NULL) || (arg2 == NULL)) {
7255 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007256 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007257 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007258 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007259 XP_ERROR0(XPATH_INVALID_OPERAND);
7260 }
7261
7262 if (arg1 == arg2) {
7263#ifdef DEBUG_EXPR
7264 xmlGenericError(xmlGenericErrorContext,
7265 "NotEqual: by pointer\n");
7266#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007267 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007268 return(0);
7269 }
7270
7271 /*
7272 *If either argument is a nodeset, it's a 'special case'
7273 */
7274 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7275 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7276 /*
7277 *Hack it to assure arg1 is the nodeset
7278 */
7279 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7280 argtmp = arg2;
7281 arg2 = arg1;
7282 arg1 = argtmp;
7283 }
7284 switch (arg2->type) {
7285 case XPATH_UNDEFINED:
7286#ifdef DEBUG_EXPR
7287 xmlGenericError(xmlGenericErrorContext,
7288 "NotEqual: undefined\n");
7289#endif
7290 break;
7291 case XPATH_NODESET:
7292 case XPATH_XSLT_TREE:
7293 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7294 break;
7295 case XPATH_BOOLEAN:
7296 if ((arg1->nodesetval == NULL) ||
7297 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007298 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007299 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007300 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007301 break;
7302 case XPATH_NUMBER:
7303 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7304 break;
7305 case XPATH_STRING:
7306 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7307 break;
7308 case XPATH_USERS:
7309 case XPATH_POINT:
7310 case XPATH_RANGE:
7311 case XPATH_LOCATIONSET:
7312 TODO
7313 break;
7314 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007315 xmlXPathReleaseObject(ctxt->context, arg1);
7316 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007317 return(ret);
7318 }
7319
7320 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7321}
Owen Taylor3473f882001-02-23 17:55:21 +00007322
7323/**
7324 * xmlXPathCompareValues:
7325 * @ctxt: the XPath Parser context
7326 * @inf: less than (1) or greater than (0)
7327 * @strict: is the comparison strict
7328 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007329 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007330 * @arg1 < @arg2 (1, 1, ...
7331 * @arg1 <= @arg2 (1, 0, ...
7332 * @arg1 > @arg2 (0, 1, ...
7333 * @arg1 >= @arg2 (0, 0, ...
7334 *
7335 * When neither object to be compared is a node-set and the operator is
7336 * <=, <, >=, >, then the objects are compared by converted both objects
7337 * to numbers and comparing the numbers according to IEEE 754. The <
7338 * comparison will be true if and only if the first number is less than the
7339 * second number. The <= comparison will be true if and only if the first
7340 * number is less than or equal to the second number. The > comparison
7341 * will be true if and only if the first number is greater than the second
7342 * number. The >= comparison will be true if and only if the first number
7343 * is greater than or equal to the second number.
7344 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007345 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007346 */
7347int
7348xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007349 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007350 xmlXPathObjectPtr arg1, arg2;
7351
Daniel Veillard6128c012004-11-08 17:16:15 +00007352 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007353 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007354 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007355 if ((arg1 == NULL) || (arg2 == NULL)) {
7356 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007357 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007358 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007359 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007360 XP_ERROR0(XPATH_INVALID_OPERAND);
7361 }
7362
William M. Brack0c022ad2002-07-12 00:56:01 +00007363 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7364 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007365 /*
7366 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7367 * are not freed from within this routine; they will be freed from the
7368 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7369 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007370 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7371 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007372 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007373 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007374 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007375 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7376 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007377 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007378 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7379 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007380 }
7381 }
7382 return(ret);
7383 }
7384
7385 if (arg1->type != XPATH_NUMBER) {
7386 valuePush(ctxt, arg1);
7387 xmlXPathNumberFunction(ctxt, 1);
7388 arg1 = valuePop(ctxt);
7389 }
7390 if (arg1->type != XPATH_NUMBER) {
7391 xmlXPathFreeObject(arg1);
7392 xmlXPathFreeObject(arg2);
7393 XP_ERROR0(XPATH_INVALID_OPERAND);
7394 }
7395 if (arg2->type != XPATH_NUMBER) {
7396 valuePush(ctxt, arg2);
7397 xmlXPathNumberFunction(ctxt, 1);
7398 arg2 = valuePop(ctxt);
7399 }
7400 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007401 xmlXPathReleaseObject(ctxt->context, arg1);
7402 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007403 XP_ERROR0(XPATH_INVALID_OPERAND);
7404 }
7405 /*
7406 * Add tests for infinity and nan
7407 * => feedback on 3.4 for Inf and NaN
7408 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007409 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007410 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007411 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007412 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007413 arg1i=xmlXPathIsInf(arg1->floatval);
7414 arg2i=xmlXPathIsInf(arg2->floatval);
7415 if (inf && strict) {
7416 if ((arg1i == -1 && arg2i != -1) ||
7417 (arg2i == 1 && arg1i != 1)) {
7418 ret = 1;
7419 } else if (arg1i == 0 && arg2i == 0) {
7420 ret = (arg1->floatval < arg2->floatval);
7421 } else {
7422 ret = 0;
7423 }
7424 }
7425 else if (inf && !strict) {
7426 if (arg1i == -1 || arg2i == 1) {
7427 ret = 1;
7428 } else if (arg1i == 0 && arg2i == 0) {
7429 ret = (arg1->floatval <= arg2->floatval);
7430 } else {
7431 ret = 0;
7432 }
7433 }
7434 else if (!inf && strict) {
7435 if ((arg1i == 1 && arg2i != 1) ||
7436 (arg2i == -1 && arg1i != -1)) {
7437 ret = 1;
7438 } else if (arg1i == 0 && arg2i == 0) {
7439 ret = (arg1->floatval > arg2->floatval);
7440 } else {
7441 ret = 0;
7442 }
7443 }
7444 else if (!inf && !strict) {
7445 if (arg1i == 1 || arg2i == -1) {
7446 ret = 1;
7447 } else if (arg1i == 0 && arg2i == 0) {
7448 ret = (arg1->floatval >= arg2->floatval);
7449 } else {
7450 ret = 0;
7451 }
7452 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007453 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007454 xmlXPathReleaseObject(ctxt->context, arg1);
7455 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007456 return(ret);
7457}
7458
7459/**
7460 * xmlXPathValueFlipSign:
7461 * @ctxt: the XPath Parser context
7462 *
7463 * Implement the unary - operation on an XPath object
7464 * The numeric operators convert their operands to numbers as if
7465 * by calling the number function.
7466 */
7467void
7468xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007469 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007470 CAST_TO_NUMBER;
7471 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007472 if (xmlXPathIsNaN(ctxt->value->floatval))
7473 ctxt->value->floatval=xmlXPathNAN;
7474 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7475 ctxt->value->floatval=xmlXPathNINF;
7476 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7477 ctxt->value->floatval=xmlXPathPINF;
7478 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007479 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7480 ctxt->value->floatval = xmlXPathNZERO;
7481 else
7482 ctxt->value->floatval = 0;
7483 }
7484 else
7485 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007486}
7487
7488/**
7489 * xmlXPathAddValues:
7490 * @ctxt: the XPath Parser context
7491 *
7492 * Implement the add operation on XPath objects:
7493 * The numeric operators convert their operands to numbers as if
7494 * by calling the number function.
7495 */
7496void
7497xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7498 xmlXPathObjectPtr arg;
7499 double val;
7500
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007501 arg = valuePop(ctxt);
7502 if (arg == NULL)
7503 XP_ERROR(XPATH_INVALID_OPERAND);
7504 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007505 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007506 CAST_TO_NUMBER;
7507 CHECK_TYPE(XPATH_NUMBER);
7508 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007509}
7510
7511/**
7512 * xmlXPathSubValues:
7513 * @ctxt: the XPath Parser context
7514 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007515 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007516 * The numeric operators convert their operands to numbers as if
7517 * by calling the number function.
7518 */
7519void
7520xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7521 xmlXPathObjectPtr arg;
7522 double val;
7523
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007524 arg = valuePop(ctxt);
7525 if (arg == NULL)
7526 XP_ERROR(XPATH_INVALID_OPERAND);
7527 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007528 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007529 CAST_TO_NUMBER;
7530 CHECK_TYPE(XPATH_NUMBER);
7531 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007532}
7533
7534/**
7535 * xmlXPathMultValues:
7536 * @ctxt: the XPath Parser context
7537 *
7538 * Implement the multiply operation on XPath objects:
7539 * The numeric operators convert their operands to numbers as if
7540 * by calling the number function.
7541 */
7542void
7543xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7544 xmlXPathObjectPtr arg;
7545 double val;
7546
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007547 arg = valuePop(ctxt);
7548 if (arg == NULL)
7549 XP_ERROR(XPATH_INVALID_OPERAND);
7550 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007551 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007552 CAST_TO_NUMBER;
7553 CHECK_TYPE(XPATH_NUMBER);
7554 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007555}
7556
7557/**
7558 * xmlXPathDivValues:
7559 * @ctxt: the XPath Parser context
7560 *
7561 * Implement the div operation on XPath objects @arg1 / @arg2:
7562 * The numeric operators convert their operands to numbers as if
7563 * by calling the number function.
7564 */
7565void
7566xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7567 xmlXPathObjectPtr arg;
7568 double val;
7569
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007570 arg = valuePop(ctxt);
7571 if (arg == NULL)
7572 XP_ERROR(XPATH_INVALID_OPERAND);
7573 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007574 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007575 CAST_TO_NUMBER;
7576 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007577 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7578 ctxt->value->floatval = xmlXPathNAN;
7579 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007580 if (ctxt->value->floatval == 0)
7581 ctxt->value->floatval = xmlXPathNAN;
7582 else if (ctxt->value->floatval > 0)
7583 ctxt->value->floatval = xmlXPathNINF;
7584 else if (ctxt->value->floatval < 0)
7585 ctxt->value->floatval = xmlXPathPINF;
7586 }
7587 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007588 if (ctxt->value->floatval == 0)
7589 ctxt->value->floatval = xmlXPathNAN;
7590 else if (ctxt->value->floatval > 0)
7591 ctxt->value->floatval = xmlXPathPINF;
7592 else if (ctxt->value->floatval < 0)
7593 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007594 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007595 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007596}
7597
7598/**
7599 * xmlXPathModValues:
7600 * @ctxt: the XPath Parser context
7601 *
7602 * Implement the mod operation on XPath objects: @arg1 / @arg2
7603 * The numeric operators convert their operands to numbers as if
7604 * by calling the number function.
7605 */
7606void
7607xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7608 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007609 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007610
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007611 arg = valuePop(ctxt);
7612 if (arg == NULL)
7613 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007614 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007615 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007616 CAST_TO_NUMBER;
7617 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007618 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007619 if (arg2 == 0)
7620 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007621 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007622 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007623 }
Owen Taylor3473f882001-02-23 17:55:21 +00007624}
7625
7626/************************************************************************
7627 * *
7628 * The traversal functions *
7629 * *
7630 ************************************************************************/
7631
Owen Taylor3473f882001-02-23 17:55:21 +00007632/*
7633 * A traversal function enumerates nodes along an axis.
7634 * Initially it must be called with NULL, and it indicates
7635 * termination on the axis by returning NULL.
7636 */
7637typedef xmlNodePtr (*xmlXPathTraversalFunction)
7638 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7639
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007640/*
7641 * xmlXPathTraversalFunctionExt:
7642 * A traversal function enumerates nodes along an axis.
7643 * Initially it must be called with NULL, and it indicates
7644 * termination on the axis by returning NULL.
7645 * The context node of the traversal is specified via @contextNode.
7646 */
7647typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7648 (xmlNodePtr cur, xmlNodePtr contextNode);
7649
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007650/*
7651 * xmlXPathNodeSetMergeFunction:
7652 * Used for merging node sets in xmlXPathCollectAndTest().
7653 */
7654typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7655 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7656
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007657
Owen Taylor3473f882001-02-23 17:55:21 +00007658/**
7659 * xmlXPathNextSelf:
7660 * @ctxt: the XPath Parser context
7661 * @cur: the current node in the traversal
7662 *
7663 * Traversal function for the "self" direction
7664 * The self axis contains just the context node itself
7665 *
7666 * Returns the next element following that axis
7667 */
7668xmlNodePtr
7669xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007670 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007671 if (cur == NULL)
7672 return(ctxt->context->node);
7673 return(NULL);
7674}
7675
7676/**
7677 * xmlXPathNextChild:
7678 * @ctxt: the XPath Parser context
7679 * @cur: the current node in the traversal
7680 *
7681 * Traversal function for the "child" direction
7682 * The child axis contains the children of the context node in document order.
7683 *
7684 * Returns the next element following that axis
7685 */
7686xmlNodePtr
7687xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007688 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007689 if (cur == NULL) {
7690 if (ctxt->context->node == NULL) return(NULL);
7691 switch (ctxt->context->node->type) {
7692 case XML_ELEMENT_NODE:
7693 case XML_TEXT_NODE:
7694 case XML_CDATA_SECTION_NODE:
7695 case XML_ENTITY_REF_NODE:
7696 case XML_ENTITY_NODE:
7697 case XML_PI_NODE:
7698 case XML_COMMENT_NODE:
7699 case XML_NOTATION_NODE:
7700 case XML_DTD_NODE:
7701 return(ctxt->context->node->children);
7702 case XML_DOCUMENT_NODE:
7703 case XML_DOCUMENT_TYPE_NODE:
7704 case XML_DOCUMENT_FRAG_NODE:
7705 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007706#ifdef LIBXML_DOCB_ENABLED
7707 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007708#endif
7709 return(((xmlDocPtr) ctxt->context->node)->children);
7710 case XML_ELEMENT_DECL:
7711 case XML_ATTRIBUTE_DECL:
7712 case XML_ENTITY_DECL:
7713 case XML_ATTRIBUTE_NODE:
7714 case XML_NAMESPACE_DECL:
7715 case XML_XINCLUDE_START:
7716 case XML_XINCLUDE_END:
7717 return(NULL);
7718 }
7719 return(NULL);
7720 }
7721 if ((cur->type == XML_DOCUMENT_NODE) ||
7722 (cur->type == XML_HTML_DOCUMENT_NODE))
7723 return(NULL);
7724 return(cur->next);
7725}
7726
7727/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007728 * xmlXPathNextChildElement:
7729 * @ctxt: the XPath Parser context
7730 * @cur: the current node in the traversal
7731 *
7732 * Traversal function for the "child" direction and nodes of type element.
7733 * The child axis contains the children of the context node in document order.
7734 *
7735 * Returns the next element following that axis
7736 */
7737static xmlNodePtr
7738xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7739 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7740 if (cur == NULL) {
7741 cur = ctxt->context->node;
7742 if (cur == NULL) return(NULL);
7743 /*
7744 * Get the first element child.
7745 */
7746 switch (cur->type) {
7747 case XML_ELEMENT_NODE:
7748 case XML_DOCUMENT_FRAG_NODE:
7749 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7750 case XML_ENTITY_NODE:
7751 cur = cur->children;
7752 if (cur != NULL) {
7753 if (cur->type == XML_ELEMENT_NODE)
7754 return(cur);
7755 do {
7756 cur = cur->next;
7757 } while ((cur != NULL) &&
7758 (cur->type != XML_ELEMENT_NODE));
7759 return(cur);
7760 }
7761 return(NULL);
7762 case XML_DOCUMENT_NODE:
7763 case XML_HTML_DOCUMENT_NODE:
7764#ifdef LIBXML_DOCB_ENABLED
7765 case XML_DOCB_DOCUMENT_NODE:
7766#endif
7767 return(xmlDocGetRootElement((xmlDocPtr) cur));
7768 default:
7769 return(NULL);
7770 }
7771 return(NULL);
7772 }
7773 /*
7774 * Get the next sibling element node.
7775 */
7776 switch (cur->type) {
7777 case XML_ELEMENT_NODE:
7778 case XML_TEXT_NODE:
7779 case XML_ENTITY_REF_NODE:
7780 case XML_ENTITY_NODE:
7781 case XML_CDATA_SECTION_NODE:
7782 case XML_PI_NODE:
7783 case XML_COMMENT_NODE:
7784 case XML_XINCLUDE_END:
7785 break;
7786 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7787 default:
7788 return(NULL);
7789 }
7790 if (cur->next != NULL) {
7791 if (cur->next->type == XML_ELEMENT_NODE)
7792 return(cur->next);
7793 cur = cur->next;
7794 do {
7795 cur = cur->next;
7796 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7797 return(cur);
7798 }
7799 return(NULL);
7800}
7801
Daniel Veillard76516062012-09-11 14:02:08 +08007802#if 0
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007803/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007804 * xmlXPathNextDescendantOrSelfElemParent:
7805 * @ctxt: the XPath Parser context
7806 * @cur: the current node in the traversal
7807 *
7808 * Traversal function for the "descendant-or-self" axis.
7809 * Additionally it returns only nodes which can be parents of
7810 * element nodes.
7811 *
7812 *
7813 * Returns the next element following that axis
7814 */
7815static xmlNodePtr
7816xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7817 xmlNodePtr contextNode)
7818{
7819 if (cur == NULL) {
7820 if (contextNode == NULL)
7821 return(NULL);
7822 switch (contextNode->type) {
7823 case XML_ELEMENT_NODE:
7824 case XML_XINCLUDE_START:
7825 case XML_DOCUMENT_FRAG_NODE:
7826 case XML_DOCUMENT_NODE:
7827#ifdef LIBXML_DOCB_ENABLED
7828 case XML_DOCB_DOCUMENT_NODE:
7829#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007830 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007831 return(contextNode);
7832 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007833 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007834 }
7835 return(NULL);
7836 } else {
7837 xmlNodePtr start = cur;
7838
7839 while (cur != NULL) {
7840 switch (cur->type) {
7841 case XML_ELEMENT_NODE:
7842 /* TODO: OK to have XInclude here? */
7843 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007844 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007845 if (cur != start)
7846 return(cur);
7847 if (cur->children != NULL) {
7848 cur = cur->children;
7849 continue;
7850 }
7851 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007852 /* Not sure if we need those here. */
7853 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007854#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007855 case XML_DOCB_DOCUMENT_NODE:
7856#endif
7857 case XML_HTML_DOCUMENT_NODE:
7858 if (cur != start)
7859 return(cur);
7860 return(xmlDocGetRootElement((xmlDocPtr) cur));
7861 default:
7862 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007863 }
7864
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007865next_sibling:
7866 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007867 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007868 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007869 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007870 } else {
7871 cur = cur->parent;
7872 goto next_sibling;
7873 }
7874 }
7875 }
7876 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007877}
Daniel Veillard76516062012-09-11 14:02:08 +08007878#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007879
7880/**
Owen Taylor3473f882001-02-23 17:55:21 +00007881 * xmlXPathNextDescendant:
7882 * @ctxt: the XPath Parser context
7883 * @cur: the current node in the traversal
7884 *
7885 * Traversal function for the "descendant" direction
7886 * the descendant axis contains the descendants of the context node in document
7887 * order; a descendant is a child or a child of a child and so on.
7888 *
7889 * Returns the next element following that axis
7890 */
7891xmlNodePtr
7892xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007893 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007894 if (cur == NULL) {
7895 if (ctxt->context->node == NULL)
7896 return(NULL);
7897 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7898 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7899 return(NULL);
7900
7901 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7902 return(ctxt->context->doc->children);
7903 return(ctxt->context->node->children);
7904 }
7905
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007906 if (cur->type == XML_NAMESPACE_DECL)
7907 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007908 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007909 /*
7910 * Do not descend on entities declarations
7911 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007912 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007913 cur = cur->children;
7914 /*
7915 * Skip DTDs
7916 */
7917 if (cur->type != XML_DTD_NODE)
7918 return(cur);
7919 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007920 }
7921
7922 if (cur == ctxt->context->node) return(NULL);
7923
Daniel Veillard68e9e742002-11-16 15:35:11 +00007924 while (cur->next != NULL) {
7925 cur = cur->next;
7926 if ((cur->type != XML_ENTITY_DECL) &&
7927 (cur->type != XML_DTD_NODE))
7928 return(cur);
7929 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007930
Owen Taylor3473f882001-02-23 17:55:21 +00007931 do {
7932 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007933 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007934 if (cur == ctxt->context->node) return(NULL);
7935 if (cur->next != NULL) {
7936 cur = cur->next;
7937 return(cur);
7938 }
7939 } while (cur != NULL);
7940 return(cur);
7941}
7942
7943/**
7944 * xmlXPathNextDescendantOrSelf:
7945 * @ctxt: the XPath Parser context
7946 * @cur: the current node in the traversal
7947 *
7948 * Traversal function for the "descendant-or-self" direction
7949 * the descendant-or-self axis contains the context node and the descendants
7950 * of the context node in document order; thus the context node is the first
7951 * node on the axis, and the first child of the context node is the second node
7952 * on the axis
7953 *
7954 * Returns the next element following that axis
7955 */
7956xmlNodePtr
7957xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007958 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007959 if (cur == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007960 return(ctxt->context->node);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007961
7962 if (ctxt->context->node == NULL)
7963 return(NULL);
7964 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7965 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7966 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007967
7968 return(xmlXPathNextDescendant(ctxt, cur));
7969}
7970
7971/**
7972 * xmlXPathNextParent:
7973 * @ctxt: the XPath Parser context
7974 * @cur: the current node in the traversal
7975 *
7976 * Traversal function for the "parent" direction
7977 * The parent axis contains the parent of the context node, if there is one.
7978 *
7979 * Returns the next element following that axis
7980 */
7981xmlNodePtr
7982xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007983 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007984 /*
7985 * the parent of an attribute or namespace node is the element
7986 * to which the attribute or namespace node is attached
7987 * Namespace handling !!!
7988 */
7989 if (cur == NULL) {
7990 if (ctxt->context->node == NULL) return(NULL);
7991 switch (ctxt->context->node->type) {
7992 case XML_ELEMENT_NODE:
7993 case XML_TEXT_NODE:
7994 case XML_CDATA_SECTION_NODE:
7995 case XML_ENTITY_REF_NODE:
7996 case XML_ENTITY_NODE:
7997 case XML_PI_NODE:
7998 case XML_COMMENT_NODE:
7999 case XML_NOTATION_NODE:
8000 case XML_DTD_NODE:
8001 case XML_ELEMENT_DECL:
8002 case XML_ATTRIBUTE_DECL:
8003 case XML_XINCLUDE_START:
8004 case XML_XINCLUDE_END:
8005 case XML_ENTITY_DECL:
8006 if (ctxt->context->node->parent == NULL)
8007 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008008 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008009 ((ctxt->context->node->parent->name[0] == ' ') ||
8010 (xmlStrEqual(ctxt->context->node->parent->name,
8011 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008012 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008013 return(ctxt->context->node->parent);
8014 case XML_ATTRIBUTE_NODE: {
8015 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8016
8017 return(att->parent);
8018 }
8019 case XML_DOCUMENT_NODE:
8020 case XML_DOCUMENT_TYPE_NODE:
8021 case XML_DOCUMENT_FRAG_NODE:
8022 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008023#ifdef LIBXML_DOCB_ENABLED
8024 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008025#endif
8026 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008027 case XML_NAMESPACE_DECL: {
8028 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008029
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008030 if ((ns->next != NULL) &&
8031 (ns->next->type != XML_NAMESPACE_DECL))
8032 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00008033 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008034 }
Owen Taylor3473f882001-02-23 17:55:21 +00008035 }
8036 }
8037 return(NULL);
8038}
8039
8040/**
8041 * xmlXPathNextAncestor:
8042 * @ctxt: the XPath Parser context
8043 * @cur: the current node in the traversal
8044 *
8045 * Traversal function for the "ancestor" direction
8046 * the ancestor axis contains the ancestors of the context node; the ancestors
8047 * of the context node consist of the parent of context node and the parent's
8048 * parent and so on; the nodes are ordered in reverse document order; thus the
8049 * parent is the first node on the axis, and the parent's parent is the second
8050 * node on the axis
8051 *
8052 * Returns the next element following that axis
8053 */
8054xmlNodePtr
8055xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008056 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008057 /*
8058 * the parent of an attribute or namespace node is the element
8059 * to which the attribute or namespace node is attached
8060 * !!!!!!!!!!!!!
8061 */
8062 if (cur == NULL) {
8063 if (ctxt->context->node == NULL) return(NULL);
8064 switch (ctxt->context->node->type) {
8065 case XML_ELEMENT_NODE:
8066 case XML_TEXT_NODE:
8067 case XML_CDATA_SECTION_NODE:
8068 case XML_ENTITY_REF_NODE:
8069 case XML_ENTITY_NODE:
8070 case XML_PI_NODE:
8071 case XML_COMMENT_NODE:
8072 case XML_DTD_NODE:
8073 case XML_ELEMENT_DECL:
8074 case XML_ATTRIBUTE_DECL:
8075 case XML_ENTITY_DECL:
8076 case XML_NOTATION_NODE:
8077 case XML_XINCLUDE_START:
8078 case XML_XINCLUDE_END:
8079 if (ctxt->context->node->parent == NULL)
8080 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008081 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008082 ((ctxt->context->node->parent->name[0] == ' ') ||
8083 (xmlStrEqual(ctxt->context->node->parent->name,
8084 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008085 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008086 return(ctxt->context->node->parent);
8087 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008088 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00008089
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008090 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00008091 }
8092 case XML_DOCUMENT_NODE:
8093 case XML_DOCUMENT_TYPE_NODE:
8094 case XML_DOCUMENT_FRAG_NODE:
8095 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008096#ifdef LIBXML_DOCB_ENABLED
8097 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008098#endif
8099 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008100 case XML_NAMESPACE_DECL: {
8101 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008102
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008103 if ((ns->next != NULL) &&
8104 (ns->next->type != XML_NAMESPACE_DECL))
8105 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008106 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008107 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008108 }
Owen Taylor3473f882001-02-23 17:55:21 +00008109 }
8110 return(NULL);
8111 }
8112 if (cur == ctxt->context->doc->children)
8113 return((xmlNodePtr) ctxt->context->doc);
8114 if (cur == (xmlNodePtr) ctxt->context->doc)
8115 return(NULL);
8116 switch (cur->type) {
8117 case XML_ELEMENT_NODE:
8118 case XML_TEXT_NODE:
8119 case XML_CDATA_SECTION_NODE:
8120 case XML_ENTITY_REF_NODE:
8121 case XML_ENTITY_NODE:
8122 case XML_PI_NODE:
8123 case XML_COMMENT_NODE:
8124 case XML_NOTATION_NODE:
8125 case XML_DTD_NODE:
8126 case XML_ELEMENT_DECL:
8127 case XML_ATTRIBUTE_DECL:
8128 case XML_ENTITY_DECL:
8129 case XML_XINCLUDE_START:
8130 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008131 if (cur->parent == NULL)
8132 return(NULL);
8133 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008134 ((cur->parent->name[0] == ' ') ||
8135 (xmlStrEqual(cur->parent->name,
8136 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008137 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008138 return(cur->parent);
8139 case XML_ATTRIBUTE_NODE: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008140 xmlAttrPtr att = (xmlAttrPtr) cur;
Owen Taylor3473f882001-02-23 17:55:21 +00008141
8142 return(att->parent);
8143 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008144 case XML_NAMESPACE_DECL: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008145 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008146
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008147 if ((ns->next != NULL) &&
8148 (ns->next->type != XML_NAMESPACE_DECL))
8149 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008150 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008151 return(NULL);
8152 }
Owen Taylor3473f882001-02-23 17:55:21 +00008153 case XML_DOCUMENT_NODE:
8154 case XML_DOCUMENT_TYPE_NODE:
8155 case XML_DOCUMENT_FRAG_NODE:
8156 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008157#ifdef LIBXML_DOCB_ENABLED
8158 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008159#endif
8160 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008161 }
8162 return(NULL);
8163}
8164
8165/**
8166 * xmlXPathNextAncestorOrSelf:
8167 * @ctxt: the XPath Parser context
8168 * @cur: the current node in the traversal
8169 *
8170 * Traversal function for the "ancestor-or-self" direction
8171 * he ancestor-or-self axis contains the context node and ancestors of
8172 * the context node in reverse document order; thus the context node is
8173 * the first node on the axis, and the context node's parent the second;
8174 * parent here is defined the same as with the parent axis.
8175 *
8176 * Returns the next element following that axis
8177 */
8178xmlNodePtr
8179xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008180 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008181 if (cur == NULL)
8182 return(ctxt->context->node);
8183 return(xmlXPathNextAncestor(ctxt, cur));
8184}
8185
8186/**
8187 * xmlXPathNextFollowingSibling:
8188 * @ctxt: the XPath Parser context
8189 * @cur: the current node in the traversal
8190 *
8191 * Traversal function for the "following-sibling" direction
8192 * The following-sibling axis contains the following siblings of the context
8193 * node in document order.
8194 *
8195 * Returns the next element following that axis
8196 */
8197xmlNodePtr
8198xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008199 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008200 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8201 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8202 return(NULL);
8203 if (cur == (xmlNodePtr) ctxt->context->doc)
8204 return(NULL);
8205 if (cur == NULL)
8206 return(ctxt->context->node->next);
8207 return(cur->next);
8208}
8209
8210/**
8211 * xmlXPathNextPrecedingSibling:
8212 * @ctxt: the XPath Parser context
8213 * @cur: the current node in the traversal
8214 *
8215 * Traversal function for the "preceding-sibling" direction
8216 * The preceding-sibling axis contains the preceding siblings of the context
8217 * node in reverse document order; the first preceding sibling is first on the
8218 * axis; the sibling preceding that node is the second on the axis and so on.
8219 *
8220 * Returns the next element following that axis
8221 */
8222xmlNodePtr
8223xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008224 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008225 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8226 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8227 return(NULL);
8228 if (cur == (xmlNodePtr) ctxt->context->doc)
8229 return(NULL);
8230 if (cur == NULL)
8231 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008232 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8233 cur = cur->prev;
8234 if (cur == NULL)
8235 return(ctxt->context->node->prev);
8236 }
Owen Taylor3473f882001-02-23 17:55:21 +00008237 return(cur->prev);
8238}
8239
8240/**
8241 * xmlXPathNextFollowing:
8242 * @ctxt: the XPath Parser context
8243 * @cur: the current node in the traversal
8244 *
8245 * Traversal function for the "following" direction
8246 * The following axis contains all nodes in the same document as the context
8247 * node that are after the context node in document order, excluding any
8248 * descendants and excluding attribute nodes and namespace nodes; the nodes
8249 * are ordered in document order
8250 *
8251 * Returns the next element following that axis
8252 */
8253xmlNodePtr
8254xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008255 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008256 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8257 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8258 return(cur->children);
8259
8260 if (cur == NULL) {
8261 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008262 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardea90b892010-10-22 15:50:50 +02008263 cur = cur->parent;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008264 } else if (cur->type == XML_NAMESPACE_DECL) {
8265 xmlNsPtr ns = (xmlNsPtr) cur;
8266
8267 if ((ns->next == NULL) ||
8268 (ns->next->type == XML_NAMESPACE_DECL))
8269 return (NULL);
8270 cur = (xmlNodePtr) ns->next;
8271 }
Daniel Veillard91d19752010-10-15 14:30:52 +02008272 }
Owen Taylor3473f882001-02-23 17:55:21 +00008273 if (cur == NULL) return(NULL) ; /* ERROR */
8274 if (cur->next != NULL) return(cur->next) ;
8275 do {
8276 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008277 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008278 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8279 if (cur->next != NULL) return(cur->next);
8280 } while (cur != NULL);
8281 return(cur);
8282}
8283
8284/*
8285 * xmlXPathIsAncestor:
8286 * @ancestor: the ancestor node
8287 * @node: the current node
8288 *
8289 * Check that @ancestor is a @node's ancestor
8290 *
8291 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8292 */
8293static int
8294xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8295 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008296 if (node->type == XML_NAMESPACE_DECL)
8297 return(0);
8298 if (ancestor->type == XML_NAMESPACE_DECL)
8299 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008300 /* nodes need to be in the same document */
8301 if (ancestor->doc != node->doc) return(0);
8302 /* avoid searching if ancestor or node is the root node */
8303 if (ancestor == (xmlNodePtr) node->doc) return(1);
8304 if (node == (xmlNodePtr) ancestor->doc) return(0);
8305 while (node->parent != NULL) {
8306 if (node->parent == ancestor)
8307 return(1);
8308 node = node->parent;
8309 }
8310 return(0);
8311}
8312
8313/**
8314 * xmlXPathNextPreceding:
8315 * @ctxt: the XPath Parser context
8316 * @cur: the current node in the traversal
8317 *
8318 * Traversal function for the "preceding" direction
8319 * the preceding axis contains all nodes in the same document as the context
8320 * node that are before the context node in document order, excluding any
8321 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8322 * ordered in reverse document order
8323 *
8324 * Returns the next element following that axis
8325 */
8326xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008327xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8328{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008329 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008330 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008331 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008332 if (cur->type == XML_ATTRIBUTE_NODE) {
8333 cur = cur->parent;
8334 } else if (cur->type == XML_NAMESPACE_DECL) {
8335 xmlNsPtr ns = (xmlNsPtr) cur;
8336
8337 if ((ns->next == NULL) ||
8338 (ns->next->type == XML_NAMESPACE_DECL))
8339 return (NULL);
8340 cur = (xmlNodePtr) ns->next;
8341 }
Daniel Veillardea90b892010-10-22 15:50:50 +02008342 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008343 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008344 return (NULL);
8345 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8346 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008347 do {
8348 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008349 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8350 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008351 }
8352
8353 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008354 if (cur == NULL)
8355 return (NULL);
8356 if (cur == ctxt->context->doc->children)
8357 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008358 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008359 return (cur);
8360}
8361
8362/**
8363 * xmlXPathNextPrecedingInternal:
8364 * @ctxt: the XPath Parser context
8365 * @cur: the current node in the traversal
8366 *
8367 * Traversal function for the "preceding" direction
8368 * the preceding axis contains all nodes in the same document as the context
8369 * node that are before the context node in document order, excluding any
8370 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8371 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008372 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008373 * state kept in the parser context: ctxt->ancestor.
8374 *
8375 * Returns the next element following that axis
8376 */
8377static xmlNodePtr
8378xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8379 xmlNodePtr cur)
8380{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008381 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008382 if (cur == NULL) {
8383 cur = ctxt->context->node;
8384 if (cur == NULL)
8385 return (NULL);
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008386 if (cur->type == XML_ATTRIBUTE_NODE) {
8387 cur = cur->parent;
8388 } else if (cur->type == XML_NAMESPACE_DECL) {
8389 xmlNsPtr ns = (xmlNsPtr) cur;
8390
8391 if ((ns->next == NULL) ||
8392 (ns->next->type == XML_NAMESPACE_DECL))
8393 return (NULL);
8394 cur = (xmlNodePtr) ns->next;
8395 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00008396 ctxt->ancestor = cur->parent;
8397 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008398 if (cur->type == XML_NAMESPACE_DECL)
8399 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008400 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8401 cur = cur->prev;
8402 while (cur->prev == NULL) {
8403 cur = cur->parent;
8404 if (cur == NULL)
8405 return (NULL);
8406 if (cur == ctxt->context->doc->children)
8407 return (NULL);
8408 if (cur != ctxt->ancestor)
8409 return (cur);
8410 ctxt->ancestor = cur->parent;
8411 }
8412 cur = cur->prev;
8413 while (cur->last != NULL)
8414 cur = cur->last;
8415 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008416}
8417
8418/**
8419 * xmlXPathNextNamespace:
8420 * @ctxt: the XPath Parser context
8421 * @cur: the current attribute in the traversal
8422 *
8423 * Traversal function for the "namespace" direction
8424 * the namespace axis contains the namespace nodes of the context node;
8425 * the order of nodes on this axis is implementation-defined; the axis will
8426 * be empty unless the context node is an element
8427 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008428 * We keep the XML namespace node at the end of the list.
8429 *
Owen Taylor3473f882001-02-23 17:55:21 +00008430 * Returns the next element following that axis
8431 */
8432xmlNodePtr
8433xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008434 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008435 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Nick Wellnhofer82b73032016-04-30 17:53:10 +02008436 if (cur == NULL) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008437 if (ctxt->context->tmpNsList != NULL)
8438 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008439 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008440 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008441 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008442 if (ctxt->context->tmpNsList != NULL) {
8443 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8444 ctxt->context->tmpNsNr++;
8445 }
8446 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008447 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008448 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008449 if (ctxt->context->tmpNsNr > 0) {
8450 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8451 } else {
8452 if (ctxt->context->tmpNsList != NULL)
8453 xmlFree(ctxt->context->tmpNsList);
8454 ctxt->context->tmpNsList = NULL;
8455 return(NULL);
8456 }
Owen Taylor3473f882001-02-23 17:55:21 +00008457}
8458
8459/**
8460 * xmlXPathNextAttribute:
8461 * @ctxt: the XPath Parser context
8462 * @cur: the current attribute in the traversal
8463 *
8464 * Traversal function for the "attribute" direction
8465 * TODO: support DTD inherited default attributes
8466 *
8467 * Returns the next element following that axis
8468 */
8469xmlNodePtr
8470xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008471 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008472 if (ctxt->context->node == NULL)
8473 return(NULL);
8474 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8475 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008476 if (cur == NULL) {
8477 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8478 return(NULL);
8479 return((xmlNodePtr)ctxt->context->node->properties);
8480 }
8481 return((xmlNodePtr)cur->next);
8482}
8483
8484/************************************************************************
8485 * *
8486 * NodeTest Functions *
8487 * *
8488 ************************************************************************/
8489
Owen Taylor3473f882001-02-23 17:55:21 +00008490#define IS_FUNCTION 200
8491
Owen Taylor3473f882001-02-23 17:55:21 +00008492
8493/************************************************************************
8494 * *
8495 * Implicit tree core function library *
8496 * *
8497 ************************************************************************/
8498
8499/**
8500 * xmlXPathRoot:
8501 * @ctxt: the XPath Parser context
8502 *
8503 * Initialize the context to the root of the document
8504 */
8505void
8506xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008507 if ((ctxt == NULL) || (ctxt->context == NULL))
8508 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008509 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008510 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8511 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008512}
8513
8514/************************************************************************
8515 * *
8516 * The explicit core function library *
8517 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8518 * *
8519 ************************************************************************/
8520
8521
8522/**
8523 * xmlXPathLastFunction:
8524 * @ctxt: the XPath Parser context
8525 * @nargs: the number of arguments
8526 *
8527 * Implement the last() XPath function
8528 * number last()
8529 * The last function returns the number of nodes in the context node list.
8530 */
8531void
8532xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8533 CHECK_ARITY(0);
8534 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008535 valuePush(ctxt,
8536 xmlXPathCacheNewFloat(ctxt->context,
8537 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008538#ifdef DEBUG_EXPR
8539 xmlGenericError(xmlGenericErrorContext,
8540 "last() : %d\n", ctxt->context->contextSize);
8541#endif
8542 } else {
8543 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8544 }
8545}
8546
8547/**
8548 * xmlXPathPositionFunction:
8549 * @ctxt: the XPath Parser context
8550 * @nargs: the number of arguments
8551 *
8552 * Implement the position() XPath function
8553 * number position()
8554 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008555 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008556 * will be equal to last().
8557 */
8558void
8559xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8560 CHECK_ARITY(0);
8561 if (ctxt->context->proximityPosition >= 0) {
8562 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008563 xmlXPathCacheNewFloat(ctxt->context,
8564 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008565#ifdef DEBUG_EXPR
8566 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8567 ctxt->context->proximityPosition);
8568#endif
8569 } else {
8570 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8571 }
8572}
8573
8574/**
8575 * xmlXPathCountFunction:
8576 * @ctxt: the XPath Parser context
8577 * @nargs: the number of arguments
8578 *
8579 * Implement the count() XPath function
8580 * number count(node-set)
8581 */
8582void
8583xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8584 xmlXPathObjectPtr cur;
8585
8586 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008587 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008588 ((ctxt->value->type != XPATH_NODESET) &&
8589 (ctxt->value->type != XPATH_XSLT_TREE)))
8590 XP_ERROR(XPATH_INVALID_TYPE);
8591 cur = valuePop(ctxt);
8592
Daniel Veillard911f49a2001-04-07 15:39:35 +00008593 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008594 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008595 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008596 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8597 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008598 } else {
8599 if ((cur->nodesetval->nodeNr != 1) ||
8600 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008601 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008602 } else {
8603 xmlNodePtr tmp;
8604 int i = 0;
8605
8606 tmp = cur->nodesetval->nodeTab[0];
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008607 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
Daniel Veillardfe703322001-08-14 12:18:09 +00008608 tmp = tmp->children;
8609 while (tmp != NULL) {
8610 tmp = tmp->next;
8611 i++;
8612 }
8613 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008614 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008615 }
8616 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008617 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008618}
8619
8620/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008621 * xmlXPathGetElementsByIds:
8622 * @doc: the document
8623 * @ids: a whitespace separated list of IDs
8624 *
8625 * Selects elements by their unique ID.
8626 *
8627 * Returns a node-set of selected elements.
8628 */
8629static xmlNodeSetPtr
8630xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8631 xmlNodeSetPtr ret;
8632 const xmlChar *cur = ids;
8633 xmlChar *ID;
8634 xmlAttrPtr attr;
8635 xmlNodePtr elem = NULL;
8636
Daniel Veillard7a985a12003-07-06 17:57:42 +00008637 if (ids == NULL) return(NULL);
8638
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008639 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008640 if (ret == NULL)
8641 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008642
William M. Brack76e95df2003-10-18 16:20:14 +00008643 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008644 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008645 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008646 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008647
8648 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008649 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008650 /*
8651 * We used to check the fact that the value passed
8652 * was an NCName, but this generated much troubles for
8653 * me and Aleksey Sanin, people blatantly violated that
8654 * constaint, like Visa3D spec.
8655 * if (xmlValidateNCName(ID, 1) == 0)
8656 */
8657 attr = xmlGetID(doc, ID);
8658 if (attr != NULL) {
8659 if (attr->type == XML_ATTRIBUTE_NODE)
8660 elem = attr->parent;
8661 else if (attr->type == XML_ELEMENT_NODE)
8662 elem = (xmlNodePtr) attr;
8663 else
8664 elem = NULL;
8665 if (elem != NULL)
8666 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008667 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008668 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008669 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008670
William M. Brack76e95df2003-10-18 16:20:14 +00008671 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008672 ids = cur;
8673 }
8674 return(ret);
8675}
8676
8677/**
Owen Taylor3473f882001-02-23 17:55:21 +00008678 * xmlXPathIdFunction:
8679 * @ctxt: the XPath Parser context
8680 * @nargs: the number of arguments
8681 *
8682 * Implement the id() XPath function
8683 * node-set id(object)
8684 * The id function selects elements by their unique ID
8685 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8686 * then the result is the union of the result of applying id to the
8687 * string value of each of the nodes in the argument node-set. When the
8688 * argument to id is of any other type, the argument is converted to a
8689 * string as if by a call to the string function; the string is split
8690 * into a whitespace-separated list of tokens (whitespace is any sequence
8691 * of characters matching the production S); the result is a node-set
8692 * containing the elements in the same document as the context node that
8693 * have a unique ID equal to any of the tokens in the list.
8694 */
8695void
8696xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008697 xmlChar *tokens;
8698 xmlNodeSetPtr ret;
8699 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008700
8701 CHECK_ARITY(1);
8702 obj = valuePop(ctxt);
8703 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008704 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008705 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008706 int i;
8707
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008708 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008709 /*
8710 * FIXME -- in an out-of-memory condition this will behave badly.
8711 * The solution is not clear -- we already popped an item from
8712 * ctxt, so the object is in a corrupt state.
8713 */
Owen Taylor3473f882001-02-23 17:55:21 +00008714
Daniel Veillard911f49a2001-04-07 15:39:35 +00008715 if (obj->nodesetval != NULL) {
8716 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008717 tokens =
8718 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8719 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8720 ret = xmlXPathNodeSetMerge(ret, ns);
8721 xmlXPathFreeNodeSet(ns);
8722 if (tokens != NULL)
8723 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008724 }
Owen Taylor3473f882001-02-23 17:55:21 +00008725 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008726 xmlXPathReleaseObject(ctxt->context, obj);
8727 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008728 return;
8729 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008730 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008731 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008732 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008733 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008734 return;
8735}
8736
8737/**
8738 * xmlXPathLocalNameFunction:
8739 * @ctxt: the XPath Parser context
8740 * @nargs: the number of arguments
8741 *
8742 * Implement the local-name() XPath function
8743 * string local-name(node-set?)
8744 * The local-name function returns a string containing the local part
8745 * of the name of the node in the argument node-set that is first in
8746 * document order. If the node-set is empty or the first node has no
8747 * name, an empty string is returned. If the argument is omitted it
8748 * defaults to the context node.
8749 */
8750void
8751xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8752 xmlXPathObjectPtr cur;
8753
Daniel Veillarda82b1822004-11-08 16:24:57 +00008754 if (ctxt == NULL) return;
8755
Owen Taylor3473f882001-02-23 17:55:21 +00008756 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008757 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8758 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008759 nargs = 1;
8760 }
8761
8762 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008763 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008764 ((ctxt->value->type != XPATH_NODESET) &&
8765 (ctxt->value->type != XPATH_XSLT_TREE)))
8766 XP_ERROR(XPATH_INVALID_TYPE);
8767 cur = valuePop(ctxt);
8768
Daniel Veillard911f49a2001-04-07 15:39:35 +00008769 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008770 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008771 } else {
8772 int i = 0; /* Should be first in document order !!!!! */
8773 switch (cur->nodesetval->nodeTab[i]->type) {
8774 case XML_ELEMENT_NODE:
8775 case XML_ATTRIBUTE_NODE:
8776 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008777 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008778 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008779 else
8780 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008781 xmlXPathCacheNewString(ctxt->context,
8782 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008783 break;
8784 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008785 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008786 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8787 break;
8788 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008789 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008790 }
8791 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008792 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008793}
8794
8795/**
8796 * xmlXPathNamespaceURIFunction:
8797 * @ctxt: the XPath Parser context
8798 * @nargs: the number of arguments
8799 *
8800 * Implement the namespace-uri() XPath function
8801 * string namespace-uri(node-set?)
8802 * The namespace-uri function returns a string containing the
8803 * namespace URI of the expanded name of the node in the argument
8804 * node-set that is first in document order. If the node-set is empty,
8805 * the first node has no name, or the expanded name has no namespace
8806 * URI, an empty string is returned. If the argument is omitted it
8807 * defaults to the context node.
8808 */
8809void
8810xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8811 xmlXPathObjectPtr cur;
8812
Daniel Veillarda82b1822004-11-08 16:24:57 +00008813 if (ctxt == NULL) return;
8814
Owen Taylor3473f882001-02-23 17:55:21 +00008815 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008816 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8817 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008818 nargs = 1;
8819 }
8820 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008821 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008822 ((ctxt->value->type != XPATH_NODESET) &&
8823 (ctxt->value->type != XPATH_XSLT_TREE)))
8824 XP_ERROR(XPATH_INVALID_TYPE);
8825 cur = valuePop(ctxt);
8826
Daniel Veillard911f49a2001-04-07 15:39:35 +00008827 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008828 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008829 } else {
8830 int i = 0; /* Should be first in document order !!!!! */
8831 switch (cur->nodesetval->nodeTab[i]->type) {
8832 case XML_ELEMENT_NODE:
8833 case XML_ATTRIBUTE_NODE:
8834 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008835 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008836 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008837 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008838 cur->nodesetval->nodeTab[i]->ns->href));
8839 break;
8840 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008841 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008842 }
8843 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008844 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008845}
8846
8847/**
8848 * xmlXPathNameFunction:
8849 * @ctxt: the XPath Parser context
8850 * @nargs: the number of arguments
8851 *
8852 * Implement the name() XPath function
8853 * string name(node-set?)
8854 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008855 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008856 * order. The QName must represent the name with respect to the namespace
8857 * declarations in effect on the node whose name is being represented.
8858 * Typically, this will be the form in which the name occurred in the XML
8859 * source. This need not be the case if there are namespace declarations
8860 * in effect on the node that associate multiple prefixes with the same
8861 * namespace. However, an implementation may include information about
8862 * the original prefix in its representation of nodes; in this case, an
8863 * implementation can ensure that the returned string is always the same
8864 * as the QName used in the XML source. If the argument it omitted it
8865 * defaults to the context node.
8866 * Libxml keep the original prefix so the "real qualified name" used is
8867 * returned.
8868 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008869static void
Daniel Veillard04383752001-07-08 14:27:15 +00008870xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8871{
Owen Taylor3473f882001-02-23 17:55:21 +00008872 xmlXPathObjectPtr cur;
8873
8874 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008875 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8876 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008877 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008878 }
8879
8880 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008881 if ((ctxt->value == NULL) ||
8882 ((ctxt->value->type != XPATH_NODESET) &&
8883 (ctxt->value->type != XPATH_XSLT_TREE)))
8884 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008885 cur = valuePop(ctxt);
8886
Daniel Veillard911f49a2001-04-07 15:39:35 +00008887 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008888 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008889 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008890 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008891
Daniel Veillard04383752001-07-08 14:27:15 +00008892 switch (cur->nodesetval->nodeTab[i]->type) {
8893 case XML_ELEMENT_NODE:
8894 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008895 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008896 valuePush(ctxt,
8897 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008898 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8899 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008900 valuePush(ctxt,
8901 xmlXPathCacheNewString(ctxt->context,
8902 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008903 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008904 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008905
Daniel Veillardc00cda82003-04-07 10:22:39 +00008906 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8907 cur->nodesetval->nodeTab[i]->ns->prefix,
8908 NULL, 0);
8909 if (fullname == cur->nodesetval->nodeTab[i]->name)
8910 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8911 if (fullname == NULL) {
8912 XP_ERROR(XPATH_MEMORY_ERROR);
8913 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008914 valuePush(ctxt, xmlXPathCacheWrapString(
8915 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008916 }
8917 break;
8918 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008919 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8920 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008921 xmlXPathLocalNameFunction(ctxt, 1);
8922 }
Owen Taylor3473f882001-02-23 17:55:21 +00008923 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008924 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008925}
8926
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008927
8928/**
Owen Taylor3473f882001-02-23 17:55:21 +00008929 * xmlXPathStringFunction:
8930 * @ctxt: the XPath Parser context
8931 * @nargs: the number of arguments
8932 *
8933 * Implement the string() XPath function
8934 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008935 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008936 * - A node-set is converted to a string by returning the value of
8937 * the node in the node-set that is first in document order.
8938 * If the node-set is empty, an empty string is returned.
8939 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008940 * + NaN is converted to the string NaN
8941 * + positive zero is converted to the string 0
8942 * + negative zero is converted to the string 0
8943 * + positive infinity is converted to the string Infinity
8944 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008945 * + if the number is an integer, the number is represented in
8946 * decimal form as a Number with no decimal point and no leading
8947 * zeros, preceded by a minus sign (-) if the number is negative
8948 * + otherwise, the number is represented in decimal form as a
8949 * Number including a decimal point with at least one digit
8950 * before the decimal point and at least one digit after the
8951 * decimal point, preceded by a minus sign (-) if the number
8952 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008953 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008954 * before the decimal point; beyond the one required digit
8955 * after the decimal point there must be as many, but only as
8956 * many, more digits as are needed to uniquely distinguish the
8957 * number from all other IEEE 754 numeric values.
8958 * - The boolean false value is converted to the string false.
8959 * The boolean true value is converted to the string true.
8960 *
8961 * If the argument is omitted, it defaults to a node-set with the
8962 * context node as its only member.
8963 */
8964void
8965xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8966 xmlXPathObjectPtr cur;
8967
Daniel Veillarda82b1822004-11-08 16:24:57 +00008968 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008969 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008970 valuePush(ctxt,
8971 xmlXPathCacheWrapString(ctxt->context,
8972 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008973 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008974 }
8975
8976 CHECK_ARITY(1);
8977 cur = valuePop(ctxt);
8978 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008979 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008980}
8981
8982/**
8983 * xmlXPathStringLengthFunction:
8984 * @ctxt: the XPath Parser context
8985 * @nargs: the number of arguments
8986 *
8987 * Implement the string-length() XPath function
8988 * number string-length(string?)
8989 * The string-length returns the number of characters in the string
8990 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8991 * the context node converted to a string, in other words the value
8992 * of the context node.
8993 */
8994void
8995xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8996 xmlXPathObjectPtr cur;
8997
8998 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008999 if ((ctxt == NULL) || (ctxt->context == NULL))
9000 return;
Owen Taylor3473f882001-02-23 17:55:21 +00009001 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009002 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009003 } else {
9004 xmlChar *content;
9005
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009006 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009007 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9008 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00009009 xmlFree(content);
9010 }
9011 return;
9012 }
9013 CHECK_ARITY(1);
9014 CAST_TO_STRING;
9015 CHECK_TYPE(XPATH_STRING);
9016 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009017 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00009018 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009019 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009020}
9021
9022/**
9023 * xmlXPathConcatFunction:
9024 * @ctxt: the XPath Parser context
9025 * @nargs: the number of arguments
9026 *
9027 * Implement the concat() XPath function
9028 * string concat(string, string, string*)
9029 * The concat function returns the concatenation of its arguments.
9030 */
9031void
9032xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9033 xmlXPathObjectPtr cur, newobj;
9034 xmlChar *tmp;
9035
Daniel Veillarda82b1822004-11-08 16:24:57 +00009036 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009037 if (nargs < 2) {
9038 CHECK_ARITY(2);
9039 }
9040
9041 CAST_TO_STRING;
9042 cur = valuePop(ctxt);
9043 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009044 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009045 return;
9046 }
9047 nargs--;
9048
9049 while (nargs > 0) {
9050 CAST_TO_STRING;
9051 newobj = valuePop(ctxt);
9052 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009053 xmlXPathReleaseObject(ctxt->context, newobj);
9054 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009055 XP_ERROR(XPATH_INVALID_TYPE);
9056 }
9057 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9058 newobj->stringval = cur->stringval;
9059 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009060 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00009061 nargs--;
9062 }
9063 valuePush(ctxt, cur);
9064}
9065
9066/**
9067 * xmlXPathContainsFunction:
9068 * @ctxt: the XPath Parser context
9069 * @nargs: the number of arguments
9070 *
9071 * Implement the contains() XPath function
9072 * boolean contains(string, string)
9073 * The contains function returns true if the first argument string
9074 * contains the second argument string, and otherwise returns false.
9075 */
9076void
9077xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9078 xmlXPathObjectPtr hay, needle;
9079
9080 CHECK_ARITY(2);
9081 CAST_TO_STRING;
9082 CHECK_TYPE(XPATH_STRING);
9083 needle = valuePop(ctxt);
9084 CAST_TO_STRING;
9085 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009086
Owen Taylor3473f882001-02-23 17:55:21 +00009087 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009088 xmlXPathReleaseObject(ctxt->context, hay);
9089 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009090 XP_ERROR(XPATH_INVALID_TYPE);
9091 }
9092 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009093 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009094 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009095 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9096 xmlXPathReleaseObject(ctxt->context, hay);
9097 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009098}
9099
9100/**
9101 * xmlXPathStartsWithFunction:
9102 * @ctxt: the XPath Parser context
9103 * @nargs: the number of arguments
9104 *
9105 * Implement the starts-with() XPath function
9106 * boolean starts-with(string, string)
9107 * The starts-with function returns true if the first argument string
9108 * starts with the second argument string, and otherwise returns false.
9109 */
9110void
9111xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9112 xmlXPathObjectPtr hay, needle;
9113 int n;
9114
9115 CHECK_ARITY(2);
9116 CAST_TO_STRING;
9117 CHECK_TYPE(XPATH_STRING);
9118 needle = valuePop(ctxt);
9119 CAST_TO_STRING;
9120 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009121
Owen Taylor3473f882001-02-23 17:55:21 +00009122 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009123 xmlXPathReleaseObject(ctxt->context, hay);
9124 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009125 XP_ERROR(XPATH_INVALID_TYPE);
9126 }
9127 n = xmlStrlen(needle->stringval);
9128 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009129 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009130 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009131 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9132 xmlXPathReleaseObject(ctxt->context, hay);
9133 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009134}
9135
9136/**
9137 * xmlXPathSubstringFunction:
9138 * @ctxt: the XPath Parser context
9139 * @nargs: the number of arguments
9140 *
9141 * Implement the substring() XPath function
9142 * string substring(string, number, number?)
9143 * The substring function returns the substring of the first argument
9144 * starting at the position specified in the second argument with
9145 * length specified in the third argument. For example,
9146 * substring("12345",2,3) returns "234". If the third argument is not
9147 * specified, it returns the substring starting at the position specified
9148 * in the second argument and continuing to the end of the string. For
9149 * example, substring("12345",2) returns "2345". More precisely, each
9150 * character in the string (see [3.6 Strings]) is considered to have a
9151 * numeric position: the position of the first character is 1, the position
9152 * of the second character is 2 and so on. The returned substring contains
9153 * those characters for which the position of the character is greater than
9154 * or equal to the second argument and, if the third argument is specified,
9155 * less than the sum of the second and third arguments; the comparisons
9156 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009157 * - substring("12345", 1.5, 2.6) returns "234"
9158 * - substring("12345", 0, 3) returns "12"
9159 * - substring("12345", 0 div 0, 3) returns ""
9160 * - substring("12345", 1, 0 div 0) returns ""
9161 * - substring("12345", -42, 1 div 0) returns "12345"
9162 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009163 */
9164void
9165xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9166 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009167 double le=0, in;
9168 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009169 xmlChar *ret;
9170
Owen Taylor3473f882001-02-23 17:55:21 +00009171 if (nargs < 2) {
9172 CHECK_ARITY(2);
9173 }
9174 if (nargs > 3) {
9175 CHECK_ARITY(3);
9176 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009177 /*
9178 * take care of possible last (position) argument
9179 */
Owen Taylor3473f882001-02-23 17:55:21 +00009180 if (nargs == 3) {
9181 CAST_TO_NUMBER;
9182 CHECK_TYPE(XPATH_NUMBER);
9183 len = valuePop(ctxt);
9184 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009185 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009186 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009187
Owen Taylor3473f882001-02-23 17:55:21 +00009188 CAST_TO_NUMBER;
9189 CHECK_TYPE(XPATH_NUMBER);
9190 start = valuePop(ctxt);
9191 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009192 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009193 CAST_TO_STRING;
9194 CHECK_TYPE(XPATH_STRING);
9195 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009196 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009197
Daniel Veillard97ac1312001-05-30 19:14:17 +00009198 /*
9199 * If last pos not present, calculate last position
9200 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009201 if (nargs != 3) {
9202 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009203 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009204 in = 1.0;
9205 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009206
Daniel Veillard45490ae2008-07-29 09:13:19 +00009207 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009208 * the index is NaN, the length is NaN, or both
9209 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009210 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009211 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009212 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009213 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009214 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009215 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009216 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009217 * First we go to integer form, rounding up
9218 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009219 */
9220 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009221 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009222
Daniel Veillard9e412302002-06-10 15:59:44 +00009223 if (xmlXPathIsInf(le) == 1) {
9224 l = m;
9225 if (i < 1)
9226 i = 1;
9227 }
9228 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9229 l = 0;
9230 else {
9231 l = (int) le;
9232 if (((double)l)+0.5 <= le) l++;
9233 }
9234
9235 /* Now we normalize inidices */
9236 i -= 1;
9237 l += i;
9238 if (i < 0)
9239 i = 0;
9240 if (l > m)
9241 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009242
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009243 /* number of chars to copy */
9244 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009245
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009246 ret = xmlUTF8Strsub(str->stringval, i, l);
9247 }
9248 else {
9249 ret = NULL;
9250 }
Owen Taylor3473f882001-02-23 17:55:21 +00009251 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009252 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009253 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009254 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009255 xmlFree(ret);
9256 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009257 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009258}
9259
9260/**
9261 * xmlXPathSubstringBeforeFunction:
9262 * @ctxt: the XPath Parser context
9263 * @nargs: the number of arguments
9264 *
9265 * Implement the substring-before() XPath function
9266 * string substring-before(string, string)
9267 * The substring-before function returns the substring of the first
9268 * argument string that precedes the first occurrence of the second
9269 * argument string in the first argument string, or the empty string
9270 * if the first argument string does not contain the second argument
9271 * string. For example, substring-before("1999/04/01","/") returns 1999.
9272 */
9273void
9274xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9275 xmlXPathObjectPtr str;
9276 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009277 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009278 const xmlChar *point;
9279 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009280
Owen Taylor3473f882001-02-23 17:55:21 +00009281 CHECK_ARITY(2);
9282 CAST_TO_STRING;
9283 find = valuePop(ctxt);
9284 CAST_TO_STRING;
9285 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009286
Daniel Veillardade10f22012-07-12 09:43:27 +08009287 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009288 if (target) {
9289 point = xmlStrstr(str->stringval, find->stringval);
9290 if (point) {
9291 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009292 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009293 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009294 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009295 xmlBufContent(target)));
9296 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009297 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009298 xmlXPathReleaseObject(ctxt->context, str);
9299 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009300}
9301
9302/**
9303 * xmlXPathSubstringAfterFunction:
9304 * @ctxt: the XPath Parser context
9305 * @nargs: the number of arguments
9306 *
9307 * Implement the substring-after() XPath function
9308 * string substring-after(string, string)
9309 * The substring-after function returns the substring of the first
9310 * argument string that follows the first occurrence of the second
9311 * argument string in the first argument string, or the empty stringi
9312 * if the first argument string does not contain the second argument
9313 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9314 * and substring-after("1999/04/01","19") returns 99/04/01.
9315 */
9316void
9317xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9318 xmlXPathObjectPtr str;
9319 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009320 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009321 const xmlChar *point;
9322 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009323
Owen Taylor3473f882001-02-23 17:55:21 +00009324 CHECK_ARITY(2);
9325 CAST_TO_STRING;
9326 find = valuePop(ctxt);
9327 CAST_TO_STRING;
9328 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009329
Daniel Veillardade10f22012-07-12 09:43:27 +08009330 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009331 if (target) {
9332 point = xmlStrstr(str->stringval, find->stringval);
9333 if (point) {
9334 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009335 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009336 xmlStrlen(str->stringval) - offset);
9337 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009338 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009339 xmlBufContent(target)));
9340 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009341 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009342 xmlXPathReleaseObject(ctxt->context, str);
9343 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009344}
9345
9346/**
9347 * xmlXPathNormalizeFunction:
9348 * @ctxt: the XPath Parser context
9349 * @nargs: the number of arguments
9350 *
9351 * Implement the normalize-space() XPath function
9352 * string normalize-space(string?)
9353 * The normalize-space function returns the argument string with white
9354 * space normalized by stripping leading and trailing whitespace
9355 * and replacing sequences of whitespace characters by a single
9356 * space. Whitespace characters are the same allowed by the S production
9357 * in XML. If the argument is omitted, it defaults to the context
9358 * node converted to a string, in other words the value of the context node.
9359 */
9360void
9361xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9362 xmlXPathObjectPtr obj = NULL;
9363 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009364 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009365 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009366
Daniel Veillarda82b1822004-11-08 16:24:57 +00009367 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009368 if (nargs == 0) {
9369 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009370 valuePush(ctxt,
9371 xmlXPathCacheWrapString(ctxt->context,
9372 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009373 nargs = 1;
9374 }
9375
9376 CHECK_ARITY(1);
9377 CAST_TO_STRING;
9378 CHECK_TYPE(XPATH_STRING);
9379 obj = valuePop(ctxt);
9380 source = obj->stringval;
9381
Daniel Veillardade10f22012-07-12 09:43:27 +08009382 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009383 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009384
Owen Taylor3473f882001-02-23 17:55:21 +00009385 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009386 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009387 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009388
Owen Taylor3473f882001-02-23 17:55:21 +00009389 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9390 blank = 0;
9391 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009392 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009393 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009394 } else {
9395 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009396 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009397 blank = 0;
9398 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009399 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009400 }
9401 source++;
9402 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009403 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009404 xmlBufContent(target)));
9405 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009406 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009407 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009408}
9409
9410/**
9411 * xmlXPathTranslateFunction:
9412 * @ctxt: the XPath Parser context
9413 * @nargs: the number of arguments
9414 *
9415 * Implement the translate() XPath function
9416 * string translate(string, string, string)
9417 * The translate function returns the first argument string with
9418 * occurrences of characters in the second argument string replaced
9419 * by the character at the corresponding position in the third argument
9420 * string. For example, translate("bar","abc","ABC") returns the string
9421 * BAr. If there is a character in the second argument string with no
9422 * character at a corresponding position in the third argument string
9423 * (because the second argument string is longer than the third argument
9424 * string), then occurrences of that character in the first argument
9425 * string are removed. For example, translate("--aaa--","abc-","ABC")
9426 * returns "AAA". If a character occurs more than once in second
9427 * argument string, then the first occurrence determines the replacement
9428 * character. If the third argument string is longer than the second
9429 * argument string, then excess characters are ignored.
9430 */
9431void
9432xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009433 xmlXPathObjectPtr str;
9434 xmlXPathObjectPtr from;
9435 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009436 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009437 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009438 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009439 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009440 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009441
Daniel Veillarde043ee12001-04-16 14:08:07 +00009442 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009443
Daniel Veillarde043ee12001-04-16 14:08:07 +00009444 CAST_TO_STRING;
9445 to = valuePop(ctxt);
9446 CAST_TO_STRING;
9447 from = valuePop(ctxt);
9448 CAST_TO_STRING;
9449 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009450
Daniel Veillardade10f22012-07-12 09:43:27 +08009451 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009452 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009453 max = xmlUTF8Strlen(to->stringval);
9454 for (cptr = str->stringval; (ch=*cptr); ) {
9455 offset = xmlUTF8Strloc(from->stringval, cptr);
9456 if (offset >= 0) {
9457 if (offset < max) {
9458 point = xmlUTF8Strpos(to->stringval, offset);
9459 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009460 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009461 }
9462 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009463 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009464
9465 /* Step to next character in input */
9466 cptr++;
9467 if ( ch & 0x80 ) {
9468 /* if not simple ascii, verify proper format */
9469 if ( (ch & 0xc0) != 0xc0 ) {
9470 xmlGenericError(xmlGenericErrorContext,
9471 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009472 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009473 break;
9474 }
9475 /* then skip over remaining bytes for this char */
9476 while ( (ch <<= 1) & 0x80 )
9477 if ( (*cptr++ & 0xc0) != 0x80 ) {
9478 xmlGenericError(xmlGenericErrorContext,
9479 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009480 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009481 break;
9482 }
9483 if (ch & 0x80) /* must have had error encountered */
9484 break;
9485 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009486 }
Owen Taylor3473f882001-02-23 17:55:21 +00009487 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009488 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009489 xmlBufContent(target)));
9490 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009491 xmlXPathReleaseObject(ctxt->context, str);
9492 xmlXPathReleaseObject(ctxt->context, from);
9493 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009494}
9495
9496/**
9497 * xmlXPathBooleanFunction:
9498 * @ctxt: the XPath Parser context
9499 * @nargs: the number of arguments
9500 *
9501 * Implement the boolean() XPath function
9502 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009503 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009504 * - a number is true if and only if it is neither positive or
9505 * negative zero nor NaN
9506 * - a node-set is true if and only if it is non-empty
9507 * - a string is true if and only if its length is non-zero
9508 */
9509void
9510xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9511 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009512
9513 CHECK_ARITY(1);
9514 cur = valuePop(ctxt);
9515 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009516 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009517 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009518}
9519
9520/**
9521 * xmlXPathNotFunction:
9522 * @ctxt: the XPath Parser context
9523 * @nargs: the number of arguments
9524 *
9525 * Implement the not() XPath function
9526 * boolean not(boolean)
9527 * The not function returns true if its argument is false,
9528 * and false otherwise.
9529 */
9530void
9531xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9532 CHECK_ARITY(1);
9533 CAST_TO_BOOLEAN;
9534 CHECK_TYPE(XPATH_BOOLEAN);
9535 ctxt->value->boolval = ! ctxt->value->boolval;
9536}
9537
9538/**
9539 * xmlXPathTrueFunction:
9540 * @ctxt: the XPath Parser context
9541 * @nargs: the number of arguments
9542 *
9543 * Implement the true() XPath function
9544 * boolean true()
9545 */
9546void
9547xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9548 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009549 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009550}
9551
9552/**
9553 * xmlXPathFalseFunction:
9554 * @ctxt: the XPath Parser context
9555 * @nargs: the number of arguments
9556 *
9557 * Implement the false() XPath function
9558 * boolean false()
9559 */
9560void
9561xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9562 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009563 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009564}
9565
9566/**
9567 * xmlXPathLangFunction:
9568 * @ctxt: the XPath Parser context
9569 * @nargs: the number of arguments
9570 *
9571 * Implement the lang() XPath function
9572 * boolean lang(string)
9573 * The lang function returns true or false depending on whether the
9574 * language of the context node as specified by xml:lang attributes
9575 * is the same as or is a sublanguage of the language specified by
9576 * the argument string. The language of the context node is determined
9577 * by the value of the xml:lang attribute on the context node, or, if
9578 * the context node has no xml:lang attribute, by the value of the
9579 * xml:lang attribute on the nearest ancestor of the context node that
9580 * has an xml:lang attribute. If there is no such attribute, then lang
9581 * returns false. If there is such an attribute, then lang returns
9582 * true if the attribute value is equal to the argument ignoring case,
9583 * or if there is some suffix starting with - such that the attribute
9584 * value is equal to the argument ignoring that suffix of the attribute
9585 * value and ignoring case.
9586 */
9587void
9588xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009589 xmlXPathObjectPtr val = NULL;
9590 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009591 const xmlChar *lang;
9592 int ret = 0;
9593 int i;
9594
9595 CHECK_ARITY(1);
9596 CAST_TO_STRING;
9597 CHECK_TYPE(XPATH_STRING);
9598 val = valuePop(ctxt);
9599 lang = val->stringval;
9600 theLang = xmlNodeGetLang(ctxt->context->node);
9601 if ((theLang != NULL) && (lang != NULL)) {
9602 for (i = 0;lang[i] != 0;i++)
9603 if (toupper(lang[i]) != toupper(theLang[i]))
9604 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009605 if ((theLang[i] == 0) || (theLang[i] == '-'))
9606 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009607 }
9608not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009609 if (theLang != NULL)
9610 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009611
9612 xmlXPathReleaseObject(ctxt->context, val);
9613 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009614}
9615
9616/**
9617 * xmlXPathNumberFunction:
9618 * @ctxt: the XPath Parser context
9619 * @nargs: the number of arguments
9620 *
9621 * Implement the number() XPath function
9622 * number number(object?)
9623 */
9624void
9625xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9626 xmlXPathObjectPtr cur;
9627 double res;
9628
Daniel Veillarda82b1822004-11-08 16:24:57 +00009629 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009630 if (nargs == 0) {
9631 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009632 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009633 } else {
9634 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9635
9636 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009637 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009638 xmlFree(content);
9639 }
9640 return;
9641 }
9642
9643 CHECK_ARITY(1);
9644 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009645 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009646}
9647
9648/**
9649 * xmlXPathSumFunction:
9650 * @ctxt: the XPath Parser context
9651 * @nargs: the number of arguments
9652 *
9653 * Implement the sum() XPath function
9654 * number sum(node-set)
9655 * The sum function returns the sum of the values of the nodes in
9656 * the argument node-set.
9657 */
9658void
9659xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9660 xmlXPathObjectPtr cur;
9661 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009662 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009663
9664 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009665 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009666 ((ctxt->value->type != XPATH_NODESET) &&
9667 (ctxt->value->type != XPATH_XSLT_TREE)))
9668 XP_ERROR(XPATH_INVALID_TYPE);
9669 cur = valuePop(ctxt);
9670
William M. Brack08171912003-12-29 02:52:11 +00009671 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009672 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9673 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009674 }
9675 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009676 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9677 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009678}
9679
9680/**
9681 * xmlXPathFloorFunction:
9682 * @ctxt: the XPath Parser context
9683 * @nargs: the number of arguments
9684 *
9685 * Implement the floor() XPath function
9686 * number floor(number)
9687 * The floor function returns the largest (closest to positive infinity)
9688 * number that is not greater than the argument and that is an integer.
9689 */
9690void
9691xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9692 CHECK_ARITY(1);
9693 CAST_TO_NUMBER;
9694 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009695
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009696 ctxt->value->floatval = floor(ctxt->value->floatval);
Owen Taylor3473f882001-02-23 17:55:21 +00009697}
9698
9699/**
9700 * xmlXPathCeilingFunction:
9701 * @ctxt: the XPath Parser context
9702 * @nargs: the number of arguments
9703 *
9704 * Implement the ceiling() XPath function
9705 * number ceiling(number)
9706 * The ceiling function returns the smallest (closest to negative infinity)
9707 * number that is not less than the argument and that is an integer.
9708 */
9709void
9710xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Owen Taylor3473f882001-02-23 17:55:21 +00009711 CHECK_ARITY(1);
9712 CAST_TO_NUMBER;
9713 CHECK_TYPE(XPATH_NUMBER);
9714
Owen Taylor3473f882001-02-23 17:55:21 +00009715 ctxt->value->floatval = ceil(ctxt->value->floatval);
Owen Taylor3473f882001-02-23 17:55:21 +00009716}
9717
9718/**
9719 * xmlXPathRoundFunction:
9720 * @ctxt: the XPath Parser context
9721 * @nargs: the number of arguments
9722 *
9723 * Implement the round() XPath function
9724 * number round(number)
9725 * The round function returns the number that is closest to the
9726 * argument and that is an integer. If there are two such numbers,
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009727 * then the one that is closest to positive infinity is returned.
Owen Taylor3473f882001-02-23 17:55:21 +00009728 */
9729void
9730xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9731 double f;
9732
9733 CHECK_ARITY(1);
9734 CAST_TO_NUMBER;
9735 CHECK_TYPE(XPATH_NUMBER);
9736
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009737 f = ctxt->value->floatval;
9738
9739 /* Test for zero to keep negative zero unchanged. */
9740 if ((xmlXPathIsNaN(f)) || (f == 0.0))
Owen Taylor3473f882001-02-23 17:55:21 +00009741 return;
9742
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009743 if ((f >= -0.5) && (f < 0.0)) {
9744 /* Negative zero. */
9745 ctxt->value->floatval = xmlXPathNZERO;
9746 }
9747 else {
9748 double rounded = floor(f);
9749 if (f - rounded >= 0.5)
9750 rounded += 1.0;
9751 ctxt->value->floatval = rounded;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009752 }
Owen Taylor3473f882001-02-23 17:55:21 +00009753}
9754
9755/************************************************************************
9756 * *
9757 * The Parser *
9758 * *
9759 ************************************************************************/
9760
9761/*
William M. Brack08171912003-12-29 02:52:11 +00009762 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009763 * implementation.
9764 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009765static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009766static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009767static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009768static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009769static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9770 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009771
9772/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009773 * xmlXPathCurrentChar:
9774 * @ctxt: the XPath parser context
9775 * @cur: pointer to the beginning of the char
9776 * @len: pointer to the length of the char read
9777 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009778 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009779 * bytes in the input buffer.
9780 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009781 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009782 */
9783
9784static int
9785xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9786 unsigned char c;
9787 unsigned int val;
9788 const xmlChar *cur;
9789
9790 if (ctxt == NULL)
9791 return(0);
9792 cur = ctxt->cur;
9793
9794 /*
9795 * We are supposed to handle UTF8, check it's valid
9796 * From rfc2044: encoding of the Unicode values on UTF-8:
9797 *
9798 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9799 * 0000 0000-0000 007F 0xxxxxxx
9800 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009801 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009802 *
9803 * Check for the 0x110000 limit too
9804 */
9805 c = *cur;
9806 if (c & 0x80) {
9807 if ((cur[1] & 0xc0) != 0x80)
9808 goto encoding_error;
9809 if ((c & 0xe0) == 0xe0) {
9810
9811 if ((cur[2] & 0xc0) != 0x80)
9812 goto encoding_error;
9813 if ((c & 0xf0) == 0xf0) {
9814 if (((c & 0xf8) != 0xf0) ||
9815 ((cur[3] & 0xc0) != 0x80))
9816 goto encoding_error;
9817 /* 4-byte code */
9818 *len = 4;
9819 val = (cur[0] & 0x7) << 18;
9820 val |= (cur[1] & 0x3f) << 12;
9821 val |= (cur[2] & 0x3f) << 6;
9822 val |= cur[3] & 0x3f;
9823 } else {
9824 /* 3-byte code */
9825 *len = 3;
9826 val = (cur[0] & 0xf) << 12;
9827 val |= (cur[1] & 0x3f) << 6;
9828 val |= cur[2] & 0x3f;
9829 }
9830 } else {
9831 /* 2-byte code */
9832 *len = 2;
9833 val = (cur[0] & 0x1f) << 6;
9834 val |= cur[1] & 0x3f;
9835 }
9836 if (!IS_CHAR(val)) {
9837 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009838 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009839 return(val);
9840 } else {
9841 /* 1-byte code */
9842 *len = 1;
9843 return((int) *cur);
9844 }
9845encoding_error:
9846 /*
William M. Brack08171912003-12-29 02:52:11 +00009847 * If we detect an UTF8 error that probably means that the
9848 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009849 * declaration header. Report the error and switch the encoding
9850 * to ISO-Latin-1 (if you don't like this policy, just declare the
9851 * encoding !)
9852 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009853 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009854 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009855}
9856
9857/**
Owen Taylor3473f882001-02-23 17:55:21 +00009858 * xmlXPathParseNCName:
9859 * @ctxt: the XPath Parser context
9860 *
9861 * parse an XML namespace non qualified name.
9862 *
9863 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9864 *
9865 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9866 * CombiningChar | Extender
9867 *
9868 * Returns the namespace name or NULL
9869 */
9870
9871xmlChar *
9872xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009873 const xmlChar *in;
9874 xmlChar *ret;
9875 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009876
Daniel Veillarda82b1822004-11-08 16:24:57 +00009877 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009878 /*
9879 * Accelerator for simple ASCII names
9880 */
9881 in = ctxt->cur;
9882 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9883 ((*in >= 0x41) && (*in <= 0x5A)) ||
9884 (*in == '_')) {
9885 in++;
9886 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9887 ((*in >= 0x41) && (*in <= 0x5A)) ||
9888 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009889 (*in == '_') || (*in == '.') ||
9890 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009891 in++;
9892 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9893 (*in == '[') || (*in == ']') || (*in == ':') ||
9894 (*in == '@') || (*in == '*')) {
9895 count = in - ctxt->cur;
9896 if (count == 0)
9897 return(NULL);
9898 ret = xmlStrndup(ctxt->cur, count);
9899 ctxt->cur = in;
9900 return(ret);
9901 }
9902 }
9903 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009904}
9905
Daniel Veillard2156a562001-04-28 12:24:34 +00009906
Owen Taylor3473f882001-02-23 17:55:21 +00009907/**
9908 * xmlXPathParseQName:
9909 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009910 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009911 *
9912 * parse an XML qualified name
9913 *
9914 * [NS 5] QName ::= (Prefix ':')? LocalPart
9915 *
9916 * [NS 6] Prefix ::= NCName
9917 *
9918 * [NS 7] LocalPart ::= NCName
9919 *
9920 * Returns the function returns the local part, and prefix is updated
9921 * to get the Prefix if any.
9922 */
9923
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009924static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009925xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9926 xmlChar *ret = NULL;
9927
9928 *prefix = NULL;
9929 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009930 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009931 *prefix = ret;
9932 NEXT;
9933 ret = xmlXPathParseNCName(ctxt);
9934 }
9935 return(ret);
9936}
9937
9938/**
9939 * xmlXPathParseName:
9940 * @ctxt: the XPath Parser context
9941 *
9942 * parse an XML name
9943 *
9944 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9945 * CombiningChar | Extender
9946 *
9947 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9948 *
9949 * Returns the namespace name or NULL
9950 */
9951
9952xmlChar *
9953xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009954 const xmlChar *in;
9955 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009956 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009957
Daniel Veillarda82b1822004-11-08 16:24:57 +00009958 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009959 /*
9960 * Accelerator for simple ASCII names
9961 */
9962 in = ctxt->cur;
9963 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9964 ((*in >= 0x41) && (*in <= 0x5A)) ||
9965 (*in == '_') || (*in == ':')) {
9966 in++;
9967 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9968 ((*in >= 0x41) && (*in <= 0x5A)) ||
9969 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009970 (*in == '_') || (*in == '-') ||
9971 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009972 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009973 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009974 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009975 if (count > XML_MAX_NAME_LENGTH) {
9976 ctxt->cur = in;
9977 XP_ERRORNULL(XPATH_EXPR_ERROR);
9978 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009979 ret = xmlStrndup(ctxt->cur, count);
9980 ctxt->cur = in;
9981 return(ret);
9982 }
9983 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009984 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009985}
9986
Daniel Veillard61d80a22001-04-27 17:13:01 +00009987static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009988xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009989 xmlChar buf[XML_MAX_NAMELEN + 5];
9990 int len = 0, l;
9991 int c;
9992
9993 /*
9994 * Handler for more complex cases
9995 */
9996 c = CUR_CHAR(l);
9997 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009998 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9999 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +000010000 (!IS_LETTER(c) && (c != '_') &&
Nick Wellnhofere2893902016-04-21 19:19:23 +020010001 ((!qualified) || (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +000010002 return(NULL);
10003 }
10004
10005 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10006 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10007 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010008 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +000010009 (IS_COMBINING(c)) ||
10010 (IS_EXTENDER(c)))) {
10011 COPY_BUF(l,buf,len,c);
10012 NEXTL(l);
10013 c = CUR_CHAR(l);
10014 if (len >= XML_MAX_NAMELEN) {
10015 /*
10016 * Okay someone managed to make a huge name, so he's ready to pay
10017 * for the processing speed.
10018 */
10019 xmlChar *buffer;
10020 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010021
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010022 if (len > XML_MAX_NAME_LENGTH) {
10023 XP_ERRORNULL(XPATH_EXPR_ERROR);
10024 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +000010025 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010026 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010027 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010028 }
10029 memcpy(buffer, buf, len);
10030 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10031 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010032 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +000010033 (IS_COMBINING(c)) ||
10034 (IS_EXTENDER(c))) {
10035 if (len + 10 > max) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010036 if (max > XML_MAX_NAME_LENGTH) {
10037 XP_ERRORNULL(XPATH_EXPR_ERROR);
10038 }
Daniel Veillard61d80a22001-04-27 17:13:01 +000010039 max *= 2;
10040 buffer = (xmlChar *) xmlRealloc(buffer,
10041 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010042 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010043 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010044 }
10045 }
10046 COPY_BUF(l,buffer,len,c);
10047 NEXTL(l);
10048 c = CUR_CHAR(l);
10049 }
10050 buffer[len] = 0;
10051 return(buffer);
10052 }
10053 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010054 if (len == 0)
10055 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010056 return(xmlStrndup(buf, len));
10057}
Daniel Veillard3cd72402002-05-13 10:33:30 +000010058
10059#define MAX_FRAC 20
10060
Owen Taylor3473f882001-02-23 17:55:21 +000010061/**
10062 * xmlXPathStringEvalNumber:
10063 * @str: A string to scan
10064 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000010065 * [30a] Float ::= Number ('e' Digits?)?
10066 *
Owen Taylor3473f882001-02-23 17:55:21 +000010067 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010068 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010069 * [31] Digits ::= [0-9]+
10070 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010071 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +000010072 * In complement of the Number expression, this function also handles
10073 * negative values : '-' Number.
10074 *
10075 * Returns the double value.
10076 */
10077double
10078xmlXPathStringEvalNumber(const xmlChar *str) {
10079 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +000010080 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010081 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010082 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010083 int exponent = 0;
10084 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010085#ifdef __GNUC__
10086 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010087 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010088#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010089 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +000010090 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010091 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10092 return(xmlXPathNAN);
10093 }
10094 if (*cur == '-') {
10095 isneg = 1;
10096 cur++;
10097 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010098
10099#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010100 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010101 * tmp/temp is a workaround against a gcc compiler bug
10102 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010103 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010104 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010105 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010106 ret = ret * 10;
10107 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010108 ok = 1;
10109 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010110 temp = (double) tmp;
10111 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010112 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010113#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010114 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010115 while ((*cur >= '0') && (*cur <= '9')) {
10116 ret = ret * 10 + (*cur - '0');
10117 ok = 1;
10118 cur++;
10119 }
10120#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010121
Owen Taylor3473f882001-02-23 17:55:21 +000010122 if (*cur == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010123 int v, frac = 0, max;
Daniel Veillard3cd72402002-05-13 10:33:30 +000010124 double fraction = 0;
10125
Owen Taylor3473f882001-02-23 17:55:21 +000010126 cur++;
10127 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10128 return(xmlXPathNAN);
10129 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010130 while (*cur == '0') {
10131 frac = frac + 1;
10132 cur++;
10133 }
10134 max = frac + MAX_FRAC;
10135 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010136 v = (*cur - '0');
10137 fraction = fraction * 10 + v;
10138 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010139 cur++;
10140 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010141 fraction /= pow(10.0, frac);
Daniel Veillard3cd72402002-05-13 10:33:30 +000010142 ret = ret + fraction;
10143 while ((*cur >= '0') && (*cur <= '9'))
10144 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010145 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010146 if ((*cur == 'e') || (*cur == 'E')) {
10147 cur++;
10148 if (*cur == '-') {
10149 is_exponent_negative = 1;
10150 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010151 } else if (*cur == '+') {
10152 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010153 }
10154 while ((*cur >= '0') && (*cur <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010155 if (exponent < 1000000)
10156 exponent = exponent * 10 + (*cur - '0');
Bjorn Reese70a9da52001-04-21 16:57:29 +000010157 cur++;
10158 }
10159 }
William M. Brack76e95df2003-10-18 16:20:14 +000010160 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010161 if (*cur != 0) return(xmlXPathNAN);
10162 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010163 if (is_exponent_negative) exponent = -exponent;
10164 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010165 return(ret);
10166}
10167
10168/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010169 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010170 * @ctxt: the XPath Parser context
10171 *
10172 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010173 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010174 * [31] Digits ::= [0-9]+
10175 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010176 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010177 *
10178 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010179static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010180xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10181{
Owen Taylor3473f882001-02-23 17:55:21 +000010182 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010183 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010184 int exponent = 0;
10185 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010186#ifdef __GNUC__
10187 unsigned long tmp = 0;
10188 double temp;
10189#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010190
10191 CHECK_ERROR;
10192 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10193 XP_ERROR(XPATH_NUMBER_ERROR);
10194 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010195#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010196 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010197 * tmp/temp is a workaround against a gcc compiler bug
10198 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010199 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010200 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010201 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010202 ret = ret * 10;
10203 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010204 ok = 1;
10205 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010206 temp = (double) tmp;
10207 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010208 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010209#else
10210 ret = 0;
10211 while ((CUR >= '0') && (CUR <= '9')) {
10212 ret = ret * 10 + (CUR - '0');
10213 ok = 1;
10214 NEXT;
10215 }
10216#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010217 if (CUR == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010218 int v, frac = 0, max;
Phil Shaferee32ad32010-11-03 20:53:55 +010010219 double fraction = 0;
10220
Owen Taylor3473f882001-02-23 17:55:21 +000010221 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010222 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10223 XP_ERROR(XPATH_NUMBER_ERROR);
10224 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010225 while (CUR == '0') {
10226 frac = frac + 1;
10227 NEXT;
10228 }
10229 max = frac + MAX_FRAC;
10230 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
Phil Shaferee32ad32010-11-03 20:53:55 +010010231 v = (CUR - '0');
10232 fraction = fraction * 10 + v;
10233 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010234 NEXT;
10235 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010236 fraction /= pow(10.0, frac);
Phil Shaferee32ad32010-11-03 20:53:55 +010010237 ret = ret + fraction;
10238 while ((CUR >= '0') && (CUR <= '9'))
10239 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010240 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010241 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010242 NEXT;
10243 if (CUR == '-') {
10244 is_exponent_negative = 1;
10245 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010246 } else if (CUR == '+') {
10247 NEXT;
10248 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010249 while ((CUR >= '0') && (CUR <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010250 if (exponent < 1000000)
10251 exponent = exponent * 10 + (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010252 NEXT;
10253 }
10254 if (is_exponent_negative)
10255 exponent = -exponent;
10256 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010257 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010258 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010259 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010260}
10261
10262/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010263 * xmlXPathParseLiteral:
10264 * @ctxt: the XPath Parser context
10265 *
10266 * Parse a Literal
10267 *
10268 * [29] Literal ::= '"' [^"]* '"'
10269 * | "'" [^']* "'"
10270 *
10271 * Returns the value found or NULL in case of error
10272 */
10273static xmlChar *
10274xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10275 const xmlChar *q;
10276 xmlChar *ret = NULL;
10277
10278 if (CUR == '"') {
10279 NEXT;
10280 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010281 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010282 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010283 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010284 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010285 } else {
10286 ret = xmlStrndup(q, CUR_PTR - q);
10287 NEXT;
10288 }
10289 } else if (CUR == '\'') {
10290 NEXT;
10291 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010292 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010293 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010294 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010295 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010296 } else {
10297 ret = xmlStrndup(q, CUR_PTR - q);
10298 NEXT;
10299 }
10300 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010301 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010302 }
10303 return(ret);
10304}
10305
10306/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010307 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010308 * @ctxt: the XPath Parser context
10309 *
10310 * Parse a Literal and push it on the stack.
10311 *
10312 * [29] Literal ::= '"' [^"]* '"'
10313 * | "'" [^']* "'"
10314 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010315 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010316 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010317static void
10318xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010319 const xmlChar *q;
10320 xmlChar *ret = NULL;
10321
10322 if (CUR == '"') {
10323 NEXT;
10324 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010325 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010326 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010327 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010328 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10329 } else {
10330 ret = xmlStrndup(q, CUR_PTR - q);
10331 NEXT;
10332 }
10333 } else if (CUR == '\'') {
10334 NEXT;
10335 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010336 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010337 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010338 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010339 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10340 } else {
10341 ret = xmlStrndup(q, CUR_PTR - q);
10342 NEXT;
10343 }
10344 } else {
10345 XP_ERROR(XPATH_START_LITERAL_ERROR);
10346 }
10347 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010348 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010349 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010350 xmlFree(ret);
10351}
10352
10353/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010354 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010355 * @ctxt: the XPath Parser context
10356 *
10357 * Parse a VariableReference, evaluate it and push it on the stack.
10358 *
10359 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010360 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010361 * of any of the types that are possible for the value of an expression,
10362 * and may also be of additional types not specified here.
10363 *
10364 * Early evaluation is possible since:
10365 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010366 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010367 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010368 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010369 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010370static void
10371xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010372 xmlChar *name;
10373 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010374
10375 SKIP_BLANKS;
10376 if (CUR != '$') {
10377 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10378 }
10379 NEXT;
10380 name = xmlXPathParseQName(ctxt, &prefix);
10381 if (name == NULL) {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010382 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010383 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10384 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010385 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010386 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10387 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010388 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010389 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
Daniel Veillard47881282012-09-07 14:24:50 +080010390 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
Daniel Veillardb3d14912005-09-04 20:47:39 +000010391 }
Owen Taylor3473f882001-02-23 17:55:21 +000010392}
10393
10394/**
10395 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010396 * @name: a name string
10397 *
10398 * Is the name given a NodeType one.
10399 *
10400 * [38] NodeType ::= 'comment'
10401 * | 'text'
10402 * | 'processing-instruction'
10403 * | 'node'
10404 *
10405 * Returns 1 if true 0 otherwise
10406 */
10407int
10408xmlXPathIsNodeType(const xmlChar *name) {
10409 if (name == NULL)
10410 return(0);
10411
Daniel Veillard1971ee22002-01-31 20:29:19 +000010412 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010413 return(1);
10414 if (xmlStrEqual(name, BAD_CAST "text"))
10415 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010416 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010417 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010418 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010419 return(1);
10420 return(0);
10421}
10422
10423/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010424 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010425 * @ctxt: the XPath Parser context
10426 *
10427 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010428 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010429 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010430 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010431 * pushed on the stack
10432 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010433static void
10434xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010435 xmlChar *name;
10436 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010437 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010438 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010439
10440 name = xmlXPathParseQName(ctxt, &prefix);
10441 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010442 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010443 XP_ERROR(XPATH_EXPR_ERROR);
10444 }
10445 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010446#ifdef DEBUG_EXPR
10447 if (prefix == NULL)
10448 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10449 name);
10450 else
10451 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10452 prefix, name);
10453#endif
10454
Owen Taylor3473f882001-02-23 17:55:21 +000010455 if (CUR != '(') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010456 xmlFree(name);
10457 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010458 XP_ERROR(XPATH_EXPR_ERROR);
10459 }
10460 NEXT;
10461 SKIP_BLANKS;
10462
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010463 /*
10464 * Optimization for count(): we don't need the node-set to be sorted.
10465 */
10466 if ((prefix == NULL) && (name[0] == 'c') &&
10467 xmlStrEqual(name, BAD_CAST "count"))
10468 {
10469 sort = 0;
10470 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010471 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010472 if (CUR != ')') {
10473 while (CUR != 0) {
10474 int op1 = ctxt->comp->last;
10475 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010476 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010477 if (ctxt->error != XPATH_EXPRESSION_OK) {
10478 xmlFree(name);
10479 xmlFree(prefix);
10480 return;
10481 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010482 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10483 nbargs++;
10484 if (CUR == ')') break;
10485 if (CUR != ',') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010486 xmlFree(name);
10487 xmlFree(prefix);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010488 XP_ERROR(XPATH_EXPR_ERROR);
10489 }
10490 NEXT;
10491 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010492 }
Owen Taylor3473f882001-02-23 17:55:21 +000010493 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010494 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10495 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010496 NEXT;
10497 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010498}
10499
10500/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010501 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010502 * @ctxt: the XPath Parser context
10503 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010504 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010505 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010506 * | Literal
10507 * | Number
10508 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010509 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010510 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010511 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010512static void
10513xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010514 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010515 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010516 else if (CUR == '(') {
10517 NEXT;
10518 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010519 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010520 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010521 if (CUR != ')') {
10522 XP_ERROR(XPATH_EXPR_ERROR);
10523 }
10524 NEXT;
10525 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010526 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010527 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010528 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010529 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010530 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010531 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010532 }
10533 SKIP_BLANKS;
10534}
10535
10536/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010537 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010538 * @ctxt: the XPath Parser context
10539 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010540 * [20] FilterExpr ::= PrimaryExpr
10541 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010542 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010543 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010544 * Square brackets are used to filter expressions in the same way that
10545 * they are used in location paths. It is an error if the expression to
10546 * be filtered does not evaluate to a node-set. The context node list
10547 * used for evaluating the expression in square brackets is the node-set
10548 * to be filtered listed in document order.
10549 */
10550
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010551static void
10552xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10553 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010554 CHECK_ERROR;
10555 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010556
Owen Taylor3473f882001-02-23 17:55:21 +000010557 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010558 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010559 SKIP_BLANKS;
10560 }
10561
Daniel Veillard45490ae2008-07-29 09:13:19 +000010562
Owen Taylor3473f882001-02-23 17:55:21 +000010563}
10564
10565/**
10566 * xmlXPathScanName:
10567 * @ctxt: the XPath Parser context
10568 *
10569 * Trickery: parse an XML name but without consuming the input flow
10570 * Needed to avoid insanity in the parser state.
10571 *
10572 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10573 * CombiningChar | Extender
10574 *
10575 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10576 *
10577 * [6] Names ::= Name (S Name)*
10578 *
10579 * Returns the Name parsed or NULL
10580 */
10581
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010582static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010583xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010584 int len = 0, l;
10585 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010586 const xmlChar *cur;
10587 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010588
Daniel Veillard03226812004-11-01 14:55:21 +000010589 cur = ctxt->cur;
10590
10591 c = CUR_CHAR(l);
10592 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10593 (!IS_LETTER(c) && (c != '_') &&
10594 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010595 return(NULL);
10596 }
10597
Daniel Veillard03226812004-11-01 14:55:21 +000010598 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10599 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10600 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010601 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010602 (IS_COMBINING(c)) ||
10603 (IS_EXTENDER(c)))) {
10604 len += l;
10605 NEXTL(l);
10606 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010607 }
Daniel Veillard03226812004-11-01 14:55:21 +000010608 ret = xmlStrndup(cur, ctxt->cur - cur);
10609 ctxt->cur = cur;
10610 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010611}
10612
10613/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010614 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010615 * @ctxt: the XPath Parser context
10616 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010617 * [19] PathExpr ::= LocationPath
10618 * | FilterExpr
10619 * | FilterExpr '/' RelativeLocationPath
10620 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010621 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010622 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010623 * The / operator and // operators combine an arbitrary expression
10624 * and a relative location path. It is an error if the expression
10625 * does not evaluate to a node-set.
10626 * The / operator does composition in the same way as when / is
10627 * used in a location path. As in location paths, // is short for
10628 * /descendant-or-self::node()/.
10629 */
10630
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010631static void
10632xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010633 int lc = 1; /* Should we branch to LocationPath ? */
10634 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10635
10636 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010637 if ((CUR == '$') || (CUR == '(') ||
10638 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010639 (CUR == '\'') || (CUR == '"') ||
10640 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010641 lc = 0;
10642 } else if (CUR == '*') {
10643 /* relative or absolute location path */
10644 lc = 1;
10645 } else if (CUR == '/') {
10646 /* relative or absolute location path */
10647 lc = 1;
10648 } else if (CUR == '@') {
10649 /* relative abbreviated attribute location path */
10650 lc = 1;
10651 } else if (CUR == '.') {
10652 /* relative abbreviated attribute location path */
10653 lc = 1;
10654 } else {
10655 /*
10656 * Problem is finding if we have a name here whether it's:
10657 * - a nodetype
10658 * - a function call in which case it's followed by '('
10659 * - an axis in which case it's followed by ':'
10660 * - a element name
10661 * We do an a priori analysis here rather than having to
10662 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010663 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010664 * read/write/debug.
10665 */
10666 SKIP_BLANKS;
10667 name = xmlXPathScanName(ctxt);
10668 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10669#ifdef DEBUG_STEP
10670 xmlGenericError(xmlGenericErrorContext,
10671 "PathExpr: Axis\n");
10672#endif
10673 lc = 1;
10674 xmlFree(name);
10675 } else if (name != NULL) {
10676 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010677
Daniel Veillard45490ae2008-07-29 09:13:19 +000010678
Owen Taylor3473f882001-02-23 17:55:21 +000010679 while (NXT(len) != 0) {
10680 if (NXT(len) == '/') {
10681 /* element name */
10682#ifdef DEBUG_STEP
10683 xmlGenericError(xmlGenericErrorContext,
10684 "PathExpr: AbbrRelLocation\n");
10685#endif
10686 lc = 1;
10687 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010688 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010689 /* ignore blanks */
10690 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010691 } else if (NXT(len) == ':') {
10692#ifdef DEBUG_STEP
10693 xmlGenericError(xmlGenericErrorContext,
10694 "PathExpr: AbbrRelLocation\n");
10695#endif
10696 lc = 1;
10697 break;
10698 } else if ((NXT(len) == '(')) {
Nick Wellnhofer9ab01a22016-06-28 14:22:23 +020010699 /* Node Type or Function */
Owen Taylor3473f882001-02-23 17:55:21 +000010700 if (xmlXPathIsNodeType(name)) {
10701#ifdef DEBUG_STEP
10702 xmlGenericError(xmlGenericErrorContext,
10703 "PathExpr: Type search\n");
10704#endif
10705 lc = 1;
Nick Wellnhofer9ab01a22016-06-28 14:22:23 +020010706#ifdef LIBXML_XPTR_ENABLED
10707 } else if (ctxt->xptr &&
10708 xmlStrEqual(name, BAD_CAST "range-to")) {
10709 lc = 1;
10710#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010711 } else {
10712#ifdef DEBUG_STEP
10713 xmlGenericError(xmlGenericErrorContext,
10714 "PathExpr: function call\n");
10715#endif
10716 lc = 0;
10717 }
10718 break;
10719 } else if ((NXT(len) == '[')) {
10720 /* element name */
10721#ifdef DEBUG_STEP
10722 xmlGenericError(xmlGenericErrorContext,
10723 "PathExpr: AbbrRelLocation\n");
10724#endif
10725 lc = 1;
10726 break;
10727 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10728 (NXT(len) == '=')) {
10729 lc = 1;
10730 break;
10731 } else {
10732 lc = 1;
10733 break;
10734 }
10735 len++;
10736 }
10737 if (NXT(len) == 0) {
10738#ifdef DEBUG_STEP
10739 xmlGenericError(xmlGenericErrorContext,
10740 "PathExpr: AbbrRelLocation\n");
10741#endif
10742 /* element name */
10743 lc = 1;
10744 }
10745 xmlFree(name);
10746 } else {
William M. Brack08171912003-12-29 02:52:11 +000010747 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010748 XP_ERROR(XPATH_EXPR_ERROR);
10749 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010750 }
Owen Taylor3473f882001-02-23 17:55:21 +000010751
10752 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010753 if (CUR == '/') {
10754 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10755 } else {
10756 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010757 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010758 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010759 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010760 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010761 CHECK_ERROR;
10762 if ((CUR == '/') && (NXT(1) == '/')) {
10763 SKIP(2);
10764 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010765
10766 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10767 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10768 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10769
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010770 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010771 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010772 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010773 }
10774 }
10775 SKIP_BLANKS;
10776}
10777
10778/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010779 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010780 * @ctxt: the XPath Parser context
10781 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010782 * [18] UnionExpr ::= PathExpr
10783 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010784 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010785 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010786 */
10787
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010788static void
10789xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10790 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010791 CHECK_ERROR;
10792 SKIP_BLANKS;
10793 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010794 int op1 = ctxt->comp->last;
10795 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010796
10797 NEXT;
10798 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010799 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010800
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010801 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10802
Owen Taylor3473f882001-02-23 17:55:21 +000010803 SKIP_BLANKS;
10804 }
Owen Taylor3473f882001-02-23 17:55:21 +000010805}
10806
10807/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010808 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010809 * @ctxt: the XPath Parser context
10810 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010811 * [27] UnaryExpr ::= UnionExpr
10812 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010813 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010814 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010815 */
10816
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010817static void
10818xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010819 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010820 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010821
10822 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010823 while (CUR == '-') {
10824 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010825 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010826 NEXT;
10827 SKIP_BLANKS;
10828 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010829
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010830 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010831 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010832 if (found) {
10833 if (minus)
10834 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10835 else
10836 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010837 }
10838}
10839
10840/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010841 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010842 * @ctxt: the XPath Parser context
10843 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010844 * [26] MultiplicativeExpr ::= UnaryExpr
10845 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10846 * | MultiplicativeExpr 'div' UnaryExpr
10847 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010848 * [34] MultiplyOperator ::= '*'
10849 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010850 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010851 */
10852
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010853static void
10854xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10855 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010856 CHECK_ERROR;
10857 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010858 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010859 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10860 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10861 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010862 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010863
10864 if (CUR == '*') {
10865 op = 0;
10866 NEXT;
10867 } else if (CUR == 'd') {
10868 op = 1;
10869 SKIP(3);
10870 } else if (CUR == 'm') {
10871 op = 2;
10872 SKIP(3);
10873 }
10874 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010875 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010876 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010877 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010878 SKIP_BLANKS;
10879 }
10880}
10881
10882/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010883 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010884 * @ctxt: the XPath Parser context
10885 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010886 * [25] AdditiveExpr ::= MultiplicativeExpr
10887 * | AdditiveExpr '+' MultiplicativeExpr
10888 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010889 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010890 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010891 */
10892
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010893static void
10894xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010895
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010896 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010897 CHECK_ERROR;
10898 SKIP_BLANKS;
10899 while ((CUR == '+') || (CUR == '-')) {
10900 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010901 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010902
10903 if (CUR == '+') plus = 1;
10904 else plus = 0;
10905 NEXT;
10906 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010907 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010908 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010909 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010910 SKIP_BLANKS;
10911 }
10912}
10913
10914/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010915 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010916 * @ctxt: the XPath Parser context
10917 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010918 * [24] RelationalExpr ::= AdditiveExpr
10919 * | RelationalExpr '<' AdditiveExpr
10920 * | RelationalExpr '>' AdditiveExpr
10921 * | RelationalExpr '<=' AdditiveExpr
10922 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010923 *
10924 * A <= B > C is allowed ? Answer from James, yes with
10925 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10926 * which is basically what got implemented.
10927 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010928 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010929 * on the stack
10930 */
10931
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010932static void
10933xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10934 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010935 CHECK_ERROR;
10936 SKIP_BLANKS;
10937 while ((CUR == '<') ||
10938 (CUR == '>') ||
10939 ((CUR == '<') && (NXT(1) == '=')) ||
10940 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010941 int inf, strict;
10942 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010943
10944 if (CUR == '<') inf = 1;
10945 else inf = 0;
10946 if (NXT(1) == '=') strict = 0;
10947 else strict = 1;
10948 NEXT;
10949 if (!strict) NEXT;
10950 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010951 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010952 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010953 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010954 SKIP_BLANKS;
10955 }
10956}
10957
10958/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010959 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010960 * @ctxt: the XPath Parser context
10961 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010962 * [23] EqualityExpr ::= RelationalExpr
10963 * | EqualityExpr '=' RelationalExpr
10964 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010965 *
10966 * A != B != C is allowed ? Answer from James, yes with
10967 * (RelationalExpr = RelationalExpr) = RelationalExpr
10968 * (RelationalExpr != RelationalExpr) != RelationalExpr
10969 * which is basically what got implemented.
10970 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010971 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010972 *
10973 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010974static void
10975xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10976 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010977 CHECK_ERROR;
10978 SKIP_BLANKS;
10979 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010980 int eq;
10981 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010982
10983 if (CUR == '=') eq = 1;
10984 else eq = 0;
10985 NEXT;
10986 if (!eq) NEXT;
10987 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010988 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010989 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010990 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010991 SKIP_BLANKS;
10992 }
10993}
10994
10995/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010996 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010997 * @ctxt: the XPath Parser context
10998 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010999 * [22] AndExpr ::= EqualityExpr
11000 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000011001 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011002 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000011003 *
11004 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011005static void
11006xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11007 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011008 CHECK_ERROR;
11009 SKIP_BLANKS;
11010 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011011 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011012 SKIP(3);
11013 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011014 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011015 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011016 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011017 SKIP_BLANKS;
11018 }
11019}
11020
11021/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000011022 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000011023 * @ctxt: the XPath Parser context
11024 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011025 * [14] Expr ::= OrExpr
11026 * [21] OrExpr ::= AndExpr
11027 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000011028 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011029 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000011030 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011031static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011032xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011033 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011034 CHECK_ERROR;
11035 SKIP_BLANKS;
11036 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011037 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011038 SKIP(2);
11039 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011040 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011041 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011042 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011043 SKIP_BLANKS;
11044 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011045 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011046 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011047 /*
11048 * This is the main place to eliminate sorting for
11049 * operations which don't require a sorted node-set.
11050 * E.g. count().
11051 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011052 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11053 }
Owen Taylor3473f882001-02-23 17:55:21 +000011054}
11055
11056/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011057 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000011058 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011059 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000011060 *
11061 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000011062 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000011063 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011064 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000011065 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011066static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011067xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011068 int op1 = ctxt->comp->last;
11069
11070 SKIP_BLANKS;
11071 if (CUR != '[') {
11072 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11073 }
11074 NEXT;
11075 SKIP_BLANKS;
11076
11077 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011078 /*
11079 * This call to xmlXPathCompileExpr() will deactivate sorting
11080 * of the predicate result.
11081 * TODO: Sorting is still activated for filters, since I'm not
11082 * sure if needed. Normally sorting should not be needed, since
11083 * a filter can only diminish the number of items in a sequence,
11084 * but won't change its order; so if the initial sequence is sorted,
11085 * subsequent sorting is not needed.
11086 */
11087 if (! filter)
11088 xmlXPathCompileExpr(ctxt, 0);
11089 else
11090 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011091 CHECK_ERROR;
11092
11093 if (CUR != ']') {
11094 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11095 }
11096
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011097 if (filter)
11098 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11099 else
11100 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011101
11102 NEXT;
11103 SKIP_BLANKS;
11104}
11105
11106/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011107 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011108 * @ctxt: the XPath Parser context
11109 * @test: pointer to a xmlXPathTestVal
11110 * @type: pointer to a xmlXPathTypeVal
11111 * @prefix: placeholder for a possible name prefix
11112 *
11113 * [7] NodeTest ::= NameTest
11114 * | NodeType '(' ')'
11115 * | 'processing-instruction' '(' Literal ')'
11116 *
11117 * [37] NameTest ::= '*'
11118 * | NCName ':' '*'
11119 * | QName
11120 * [38] NodeType ::= 'comment'
11121 * | 'text'
11122 * | 'processing-instruction'
11123 * | 'node'
11124 *
William M. Brack08171912003-12-29 02:52:11 +000011125 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011126 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011127static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011128xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11129 xmlXPathTypeVal *type, const xmlChar **prefix,
11130 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011131 int blanks;
11132
11133 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11134 STRANGE;
11135 return(NULL);
11136 }
William M. Brack78637da2003-07-31 14:47:38 +000011137 *type = (xmlXPathTypeVal) 0;
11138 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011139 *prefix = NULL;
11140 SKIP_BLANKS;
11141
11142 if ((name == NULL) && (CUR == '*')) {
11143 /*
11144 * All elements
11145 */
11146 NEXT;
11147 *test = NODE_TEST_ALL;
11148 return(NULL);
11149 }
11150
11151 if (name == NULL)
11152 name = xmlXPathParseNCName(ctxt);
11153 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011154 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011155 }
11156
William M. Brack76e95df2003-10-18 16:20:14 +000011157 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011158 SKIP_BLANKS;
11159 if (CUR == '(') {
11160 NEXT;
11161 /*
11162 * NodeType or PI search
11163 */
11164 if (xmlStrEqual(name, BAD_CAST "comment"))
11165 *type = NODE_TYPE_COMMENT;
11166 else if (xmlStrEqual(name, BAD_CAST "node"))
11167 *type = NODE_TYPE_NODE;
11168 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11169 *type = NODE_TYPE_PI;
11170 else if (xmlStrEqual(name, BAD_CAST "text"))
11171 *type = NODE_TYPE_TEXT;
11172 else {
11173 if (name != NULL)
11174 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011175 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011176 }
11177
11178 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011179
Owen Taylor3473f882001-02-23 17:55:21 +000011180 SKIP_BLANKS;
11181 if (*type == NODE_TYPE_PI) {
11182 /*
11183 * Specific case: search a PI by name.
11184 */
Owen Taylor3473f882001-02-23 17:55:21 +000011185 if (name != NULL)
11186 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011187 name = NULL;
11188 if (CUR != ')') {
11189 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011190 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011191 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011192 SKIP_BLANKS;
11193 }
Owen Taylor3473f882001-02-23 17:55:21 +000011194 }
11195 if (CUR != ')') {
11196 if (name != NULL)
11197 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011198 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011199 }
11200 NEXT;
11201 return(name);
11202 }
11203 *test = NODE_TEST_NAME;
11204 if ((!blanks) && (CUR == ':')) {
11205 NEXT;
11206
11207 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011208 * Since currently the parser context don't have a
11209 * namespace list associated:
11210 * The namespace name for this prefix can be computed
11211 * only at evaluation time. The compilation is done
11212 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011213 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011214#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011215 *prefix = xmlXPathNsLookup(ctxt->context, name);
11216 if (name != NULL)
11217 xmlFree(name);
11218 if (*prefix == NULL) {
11219 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11220 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011221#else
11222 *prefix = name;
11223#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011224
11225 if (CUR == '*') {
11226 /*
11227 * All elements
11228 */
11229 NEXT;
11230 *test = NODE_TEST_ALL;
11231 return(NULL);
11232 }
11233
11234 name = xmlXPathParseNCName(ctxt);
11235 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011236 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011237 }
11238 }
11239 return(name);
11240}
11241
11242/**
11243 * xmlXPathIsAxisName:
11244 * @name: a preparsed name token
11245 *
11246 * [6] AxisName ::= 'ancestor'
11247 * | 'ancestor-or-self'
11248 * | 'attribute'
11249 * | 'child'
11250 * | 'descendant'
11251 * | 'descendant-or-self'
11252 * | 'following'
11253 * | 'following-sibling'
11254 * | 'namespace'
11255 * | 'parent'
11256 * | 'preceding'
11257 * | 'preceding-sibling'
11258 * | 'self'
11259 *
11260 * Returns the axis or 0
11261 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011262static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011263xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011264 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011265 switch (name[0]) {
11266 case 'a':
11267 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11268 ret = AXIS_ANCESTOR;
11269 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11270 ret = AXIS_ANCESTOR_OR_SELF;
11271 if (xmlStrEqual(name, BAD_CAST "attribute"))
11272 ret = AXIS_ATTRIBUTE;
11273 break;
11274 case 'c':
11275 if (xmlStrEqual(name, BAD_CAST "child"))
11276 ret = AXIS_CHILD;
11277 break;
11278 case 'd':
11279 if (xmlStrEqual(name, BAD_CAST "descendant"))
11280 ret = AXIS_DESCENDANT;
11281 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11282 ret = AXIS_DESCENDANT_OR_SELF;
11283 break;
11284 case 'f':
11285 if (xmlStrEqual(name, BAD_CAST "following"))
11286 ret = AXIS_FOLLOWING;
11287 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11288 ret = AXIS_FOLLOWING_SIBLING;
11289 break;
11290 case 'n':
11291 if (xmlStrEqual(name, BAD_CAST "namespace"))
11292 ret = AXIS_NAMESPACE;
11293 break;
11294 case 'p':
11295 if (xmlStrEqual(name, BAD_CAST "parent"))
11296 ret = AXIS_PARENT;
11297 if (xmlStrEqual(name, BAD_CAST "preceding"))
11298 ret = AXIS_PRECEDING;
11299 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11300 ret = AXIS_PRECEDING_SIBLING;
11301 break;
11302 case 's':
11303 if (xmlStrEqual(name, BAD_CAST "self"))
11304 ret = AXIS_SELF;
11305 break;
11306 }
11307 return(ret);
11308}
11309
11310/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011311 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011312 * @ctxt: the XPath Parser context
11313 *
11314 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011315 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011316 *
11317 * [12] AbbreviatedStep ::= '.' | '..'
11318 *
11319 * [5] AxisSpecifier ::= AxisName '::'
11320 * | AbbreviatedAxisSpecifier
11321 *
11322 * [13] AbbreviatedAxisSpecifier ::= '@'?
11323 *
11324 * Modified for XPtr range support as:
11325 *
11326 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11327 * | AbbreviatedStep
11328 * | 'range-to' '(' Expr ')' Predicate*
11329 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011330 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011331 * A location step of . is short for self::node(). This is
11332 * particularly useful in conjunction with //. For example, the
11333 * location path .//para is short for
11334 * self::node()/descendant-or-self::node()/child::para
11335 * and so will select all para descendant elements of the context
11336 * node.
11337 * Similarly, a location step of .. is short for parent::node().
11338 * For example, ../title is short for parent::node()/child::title
11339 * and so will select the title children of the parent of the context
11340 * node.
11341 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011342static void
11343xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011344#ifdef LIBXML_XPTR_ENABLED
11345 int rangeto = 0;
11346 int op2 = -1;
11347#endif
11348
Owen Taylor3473f882001-02-23 17:55:21 +000011349 SKIP_BLANKS;
11350 if ((CUR == '.') && (NXT(1) == '.')) {
11351 SKIP(2);
11352 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011353 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11354 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011355 } else if (CUR == '.') {
11356 NEXT;
11357 SKIP_BLANKS;
11358 } else {
11359 xmlChar *name = NULL;
11360 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011361 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011362 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011363 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011364 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011365
11366 /*
11367 * The modification needed for XPointer change to the production
11368 */
11369#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011370 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011371 name = xmlXPathParseNCName(ctxt);
11372 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011373 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011374 xmlFree(name);
11375 SKIP_BLANKS;
11376 if (CUR != '(') {
11377 XP_ERROR(XPATH_EXPR_ERROR);
11378 }
11379 NEXT;
11380 SKIP_BLANKS;
11381
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011382 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011383 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011384 CHECK_ERROR;
11385
11386 SKIP_BLANKS;
11387 if (CUR != ')') {
11388 XP_ERROR(XPATH_EXPR_ERROR);
11389 }
11390 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011391 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011392 goto eval_predicates;
11393 }
11394 }
11395#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011396 if (CUR == '*') {
11397 axis = AXIS_CHILD;
11398 } else {
11399 if (name == NULL)
11400 name = xmlXPathParseNCName(ctxt);
11401 if (name != NULL) {
11402 axis = xmlXPathIsAxisName(name);
11403 if (axis != 0) {
11404 SKIP_BLANKS;
11405 if ((CUR == ':') && (NXT(1) == ':')) {
11406 SKIP(2);
11407 xmlFree(name);
11408 name = NULL;
11409 } else {
11410 /* an element name can conflict with an axis one :-\ */
11411 axis = AXIS_CHILD;
11412 }
Owen Taylor3473f882001-02-23 17:55:21 +000011413 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011414 axis = AXIS_CHILD;
11415 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011416 } else if (CUR == '@') {
11417 NEXT;
11418 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011419 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011420 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011421 }
Owen Taylor3473f882001-02-23 17:55:21 +000011422 }
11423
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011424 if (ctxt->error != XPATH_EXPRESSION_OK) {
11425 xmlFree(name);
11426 return;
11427 }
Owen Taylor3473f882001-02-23 17:55:21 +000011428
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011429 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011430 if (test == 0)
11431 return;
11432
Daniel Veillarded6c5492005-07-23 15:00:22 +000011433 if ((prefix != NULL) && (ctxt->context != NULL) &&
11434 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11435 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11436 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11437 }
11438 }
Owen Taylor3473f882001-02-23 17:55:21 +000011439#ifdef DEBUG_STEP
11440 xmlGenericError(xmlGenericErrorContext,
11441 "Basis : computing new set\n");
11442#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011443
Owen Taylor3473f882001-02-23 17:55:21 +000011444#ifdef DEBUG_STEP
11445 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011446 if (ctxt->value == NULL)
11447 xmlGenericError(xmlGenericErrorContext, "no value\n");
11448 else if (ctxt->value->nodesetval == NULL)
11449 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11450 else
11451 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011452#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011453
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011454#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011455eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011456#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011457 op1 = ctxt->comp->last;
11458 ctxt->comp->last = -1;
11459
Owen Taylor3473f882001-02-23 17:55:21 +000011460 SKIP_BLANKS;
11461 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011462 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011463 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011464
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011465#ifdef LIBXML_XPTR_ENABLED
11466 if (rangeto) {
11467 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11468 } else
11469#endif
11470 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11471 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011472
Owen Taylor3473f882001-02-23 17:55:21 +000011473 }
11474#ifdef DEBUG_STEP
11475 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011476 if (ctxt->value == NULL)
11477 xmlGenericError(xmlGenericErrorContext, "no value\n");
11478 else if (ctxt->value->nodesetval == NULL)
11479 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11480 else
11481 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11482 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011483#endif
11484}
11485
11486/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011487 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011488 * @ctxt: the XPath Parser context
11489 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011490 * [3] RelativeLocationPath ::= Step
11491 * | RelativeLocationPath '/' Step
11492 * | AbbreviatedRelativeLocationPath
11493 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011494 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011495 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011496 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011497static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011498xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011499(xmlXPathParserContextPtr ctxt) {
11500 SKIP_BLANKS;
11501 if ((CUR == '/') && (NXT(1) == '/')) {
11502 SKIP(2);
11503 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011504 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11505 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011506 } else if (CUR == '/') {
11507 NEXT;
11508 SKIP_BLANKS;
11509 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011510 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011511 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011512 SKIP_BLANKS;
11513 while (CUR == '/') {
11514 if ((CUR == '/') && (NXT(1) == '/')) {
11515 SKIP(2);
11516 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011517 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011518 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011519 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011520 } else if (CUR == '/') {
11521 NEXT;
11522 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011523 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011524 }
11525 SKIP_BLANKS;
11526 }
11527}
11528
11529/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011530 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011531 * @ctxt: the XPath Parser context
11532 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011533 * [1] LocationPath ::= RelativeLocationPath
11534 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011535 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011536 * | AbbreviatedAbsoluteLocationPath
11537 * [10] AbbreviatedAbsoluteLocationPath ::=
11538 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011539 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011540 * Compile a location path
11541 *
Owen Taylor3473f882001-02-23 17:55:21 +000011542 * // is short for /descendant-or-self::node()/. For example,
11543 * //para is short for /descendant-or-self::node()/child::para and
11544 * so will select any para element in the document (even a para element
11545 * that is a document element will be selected by //para since the
11546 * document element node is a child of the root node); div//para is
11547 * short for div/descendant-or-self::node()/child::para and so will
11548 * select all para descendants of div children.
11549 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011550static void
11551xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011552 SKIP_BLANKS;
11553 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011554 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011555 } else {
11556 while (CUR == '/') {
11557 if ((CUR == '/') && (NXT(1) == '/')) {
11558 SKIP(2);
11559 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011560 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11561 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011562 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011563 } else if (CUR == '/') {
11564 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011565 SKIP_BLANKS;
11566 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011567 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011568 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011569 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011570 }
Martin729601f2009-10-12 22:42:26 +020011571 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011572 }
11573 }
11574}
11575
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011576/************************************************************************
11577 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011578 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011579 * *
11580 ************************************************************************/
11581
Daniel Veillardf06307e2001-07-03 10:35:50 +000011582static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011583xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11584
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011585#ifdef DEBUG_STEP
11586static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011587xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011588 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011589{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011590 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011591 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011592 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011593 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011594 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011595 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011596 xmlGenericError(xmlGenericErrorContext,
11597 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011598 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011599 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011600 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011601 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011602 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011603 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011604 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011605 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011606 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011607 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011608 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011609 xmlGenericError(xmlGenericErrorContext,
11610 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011611 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011612 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011613 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011614 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011615 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011616 xmlGenericError(xmlGenericErrorContext,
11617 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011618 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011619 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011620 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011621 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011622 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011623 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011624 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011625 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011626 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011627 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011628 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011629 xmlGenericError(xmlGenericErrorContext,
11630 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011631 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011632 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011633 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011634 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011635 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011636 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011637 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011638 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011639 case NODE_TEST_NONE:
11640 xmlGenericError(xmlGenericErrorContext,
11641 " searching for none !!!\n");
11642 break;
11643 case NODE_TEST_TYPE:
11644 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011645 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011646 break;
11647 case NODE_TEST_PI:
11648 xmlGenericError(xmlGenericErrorContext,
11649 " searching for PI !!!\n");
11650 break;
11651 case NODE_TEST_ALL:
11652 xmlGenericError(xmlGenericErrorContext,
11653 " searching for *\n");
11654 break;
11655 case NODE_TEST_NS:
11656 xmlGenericError(xmlGenericErrorContext,
11657 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011658 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011659 break;
11660 case NODE_TEST_NAME:
11661 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011662 " searching for name %s\n", op->value5);
11663 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011664 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011665 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011666 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011667 }
11668 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011669}
11670#endif /* DEBUG_STEP */
11671
11672static int
11673xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11674 xmlXPathStepOpPtr op,
11675 xmlNodeSetPtr set,
11676 int contextSize,
11677 int hasNsNodes)
11678{
11679 if (op->ch1 != -1) {
11680 xmlXPathCompExprPtr comp = ctxt->comp;
11681 /*
11682 * Process inner predicates first.
11683 */
11684 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11685 /*
11686 * TODO: raise an internal error.
11687 */
11688 }
11689 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11690 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11691 CHECK_ERROR0;
11692 if (contextSize <= 0)
11693 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011694 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011695 if (op->ch2 != -1) {
11696 xmlXPathContextPtr xpctxt = ctxt->context;
11697 xmlNodePtr contextNode, oldContextNode;
11698 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011699 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011700 xmlXPathStepOpPtr exprOp;
11701 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11702
11703#ifdef LIBXML_XPTR_ENABLED
11704 /*
11705 * URGENT TODO: Check the following:
11706 * We don't expect location sets if evaluating prediates, right?
11707 * Only filters should expect location sets, right?
11708 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011709#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011710 /*
11711 * SPEC XPath 1.0:
11712 * "For each node in the node-set to be filtered, the
11713 * PredicateExpr is evaluated with that node as the
11714 * context node, with the number of nodes in the
11715 * node-set as the context size, and with the proximity
11716 * position of the node in the node-set with respect to
11717 * the axis as the context position;"
11718 * @oldset is the node-set" to be filtered.
11719 *
11720 * SPEC XPath 1.0:
11721 * "only predicates change the context position and
11722 * context size (see [2.4 Predicates])."
11723 * Example:
11724 * node-set context pos
11725 * nA 1
11726 * nB 2
11727 * nC 3
11728 * After applying predicate [position() > 1] :
11729 * node-set context pos
11730 * nB 1
11731 * nC 2
11732 */
11733 oldContextNode = xpctxt->node;
11734 oldContextDoc = xpctxt->doc;
11735 /*
11736 * Get the expression of this predicate.
11737 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011738 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011739 newContextSize = 0;
11740 for (i = 0; i < set->nodeNr; i++) {
11741 if (set->nodeTab[i] == NULL)
11742 continue;
11743
11744 contextNode = set->nodeTab[i];
11745 xpctxt->node = contextNode;
11746 xpctxt->contextSize = contextSize;
11747 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011748
11749 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011750 * Also set the xpath document in case things like
11751 * key() are evaluated in the predicate.
11752 */
11753 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11754 (contextNode->doc != NULL))
11755 xpctxt->doc = contextNode->doc;
11756 /*
11757 * Evaluate the predicate expression with 1 context node
11758 * at a time; this node is packaged into a node set; this
11759 * node set is handed over to the evaluation mechanism.
11760 */
11761 if (contextObj == NULL)
11762 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011763 else {
11764 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11765 contextNode) < 0) {
11766 ctxt->error = XPATH_MEMORY_ERROR;
11767 goto evaluation_exit;
11768 }
11769 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011770
11771 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011772
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011773 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011774
William M. Brack0bcec062007-02-14 02:15:19 +000011775 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11776 xmlXPathNodeSetClear(set, hasNsNodes);
11777 newContextSize = 0;
11778 goto evaluation_exit;
11779 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011780
11781 if (res != 0) {
11782 newContextSize++;
11783 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011784 /*
11785 * Remove the entry from the initial node set.
11786 */
11787 set->nodeTab[i] = NULL;
11788 if (contextNode->type == XML_NAMESPACE_DECL)
11789 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011790 }
11791 if (ctxt->value == contextObj) {
11792 /*
11793 * Don't free the temporary XPath object holding the
11794 * context node, in order to avoid massive recreation
11795 * inside this loop.
11796 */
11797 valuePop(ctxt);
11798 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11799 } else {
11800 /*
11801 * TODO: The object was lost in the evaluation machinery.
11802 * Can this happen? Maybe in internal-error cases.
11803 */
11804 contextObj = NULL;
11805 }
11806 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011807
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011808 if (contextObj != NULL) {
11809 if (ctxt->value == contextObj)
11810 valuePop(ctxt);
11811 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011812 }
William M. Brack0bcec062007-02-14 02:15:19 +000011813evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011814 if (exprRes != NULL)
11815 xmlXPathReleaseObject(ctxt->context, exprRes);
11816 /*
11817 * Reset/invalidate the context.
11818 */
11819 xpctxt->node = oldContextNode;
11820 xpctxt->doc = oldContextDoc;
11821 xpctxt->contextSize = -1;
11822 xpctxt->proximityPosition = -1;
11823 return(newContextSize);
11824 }
11825 return(contextSize);
11826}
11827
11828static int
11829xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11830 xmlXPathStepOpPtr op,
11831 xmlNodeSetPtr set,
11832 int contextSize,
11833 int minPos,
11834 int maxPos,
11835 int hasNsNodes)
11836{
11837 if (op->ch1 != -1) {
11838 xmlXPathCompExprPtr comp = ctxt->comp;
11839 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11840 /*
11841 * TODO: raise an internal error.
11842 */
11843 }
11844 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11845 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11846 CHECK_ERROR0;
11847 if (contextSize <= 0)
11848 return(0);
11849 }
11850 /*
11851 * Check if the node set contains a sufficient number of nodes for
11852 * the requested range.
11853 */
11854 if (contextSize < minPos) {
11855 xmlXPathNodeSetClear(set, hasNsNodes);
11856 return(0);
11857 }
11858 if (op->ch2 == -1) {
11859 /*
11860 * TODO: Can this ever happen?
11861 */
11862 return (contextSize);
11863 } else {
11864 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011865 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011866 xmlXPathStepOpPtr exprOp;
11867 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11868 xmlNodePtr oldContextNode, contextNode = NULL;
11869 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011870 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011871
11872#ifdef LIBXML_XPTR_ENABLED
11873 /*
11874 * URGENT TODO: Check the following:
11875 * We don't expect location sets if evaluating prediates, right?
11876 * Only filters should expect location sets, right?
11877 */
11878#endif /* LIBXML_XPTR_ENABLED */
11879
11880 /*
11881 * Save old context.
11882 */
11883 oldContextNode = xpctxt->node;
11884 oldContextDoc = xpctxt->doc;
11885 /*
11886 * Get the expression of this predicate.
11887 */
11888 exprOp = &ctxt->comp->steps[op->ch2];
11889 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011890 xmlXPathObjectPtr tmp;
11891
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011892 if (set->nodeTab[i] == NULL)
11893 continue;
11894
11895 contextNode = set->nodeTab[i];
11896 xpctxt->node = contextNode;
11897 xpctxt->contextSize = contextSize;
11898 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011899
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011900 /*
11901 * Initialize the new set.
11902 * Also set the xpath document in case things like
11903 * key() evaluation are attempted on the predicate
11904 */
11905 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11906 (contextNode->doc != NULL))
11907 xpctxt->doc = contextNode->doc;
11908 /*
11909 * Evaluate the predicate expression with 1 context node
11910 * at a time; this node is packaged into a node set; this
11911 * node set is handed over to the evaluation mechanism.
11912 */
11913 if (contextObj == NULL)
11914 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011915 else {
11916 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11917 contextNode) < 0) {
11918 ctxt->error = XPATH_MEMORY_ERROR;
11919 goto evaluation_exit;
11920 }
11921 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011922
Daniel Veillardf5048b32011-08-18 17:10:13 +080011923 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011924 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011925 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011926 tmp = valuePop(ctxt);
11927 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011928
William M. Brackf1794562007-08-23 12:58:13 +000011929 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011930 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011931 /*
11932 * Free up the result
11933 * then pop off contextObj, which will be freed later
11934 */
11935 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011936 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011937 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011938 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011939 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011940 /* push the result back onto the stack */
11941 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011942
11943 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011944 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011945
11946 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011947 /*
11948 * Fits in the requested range.
11949 */
11950 newContextSize++;
11951 if (minPos == maxPos) {
11952 /*
11953 * Only 1 node was requested.
11954 */
11955 if (contextNode->type == XML_NAMESPACE_DECL) {
11956 /*
11957 * As always: take care of those nasty
11958 * namespace nodes.
11959 */
11960 set->nodeTab[i] = NULL;
11961 }
11962 xmlXPathNodeSetClear(set, hasNsNodes);
11963 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011964 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011965 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011966 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011967 if (pos == maxPos) {
11968 /*
11969 * We are done.
11970 */
11971 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11972 goto evaluation_exit;
11973 }
11974 } else {
11975 /*
11976 * Remove the entry from the initial node set.
11977 */
11978 set->nodeTab[i] = NULL;
11979 if (contextNode->type == XML_NAMESPACE_DECL)
11980 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11981 }
11982 if (exprRes != NULL) {
11983 xmlXPathReleaseObject(ctxt->context, exprRes);
11984 exprRes = NULL;
11985 }
11986 if (ctxt->value == contextObj) {
11987 /*
11988 * Don't free the temporary XPath object holding the
11989 * context node, in order to avoid massive recreation
11990 * inside this loop.
11991 */
11992 valuePop(ctxt);
11993 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11994 } else {
11995 /*
11996 * The object was lost in the evaluation machinery.
11997 * Can this happen? Maybe in case of internal-errors.
11998 */
11999 contextObj = NULL;
12000 }
12001 }
12002 goto evaluation_exit;
12003
12004evaluation_error:
12005 xmlXPathNodeSetClear(set, hasNsNodes);
12006 newContextSize = 0;
12007
12008evaluation_exit:
12009 if (contextObj != NULL) {
12010 if (ctxt->value == contextObj)
12011 valuePop(ctxt);
12012 xmlXPathReleaseObject(xpctxt, contextObj);
12013 }
12014 if (exprRes != NULL)
12015 xmlXPathReleaseObject(ctxt->context, exprRes);
12016 /*
12017 * Reset/invalidate the context.
12018 */
12019 xpctxt->node = oldContextNode;
12020 xpctxt->doc = oldContextDoc;
12021 xpctxt->contextSize = -1;
12022 xpctxt->proximityPosition = -1;
12023 return(newContextSize);
12024 }
12025 return(contextSize);
12026}
12027
12028static int
12029xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000012030 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012031 int *maxPos)
12032{
12033
12034 xmlXPathStepOpPtr exprOp;
12035
12036 /*
12037 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12038 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012039
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012040 /*
12041 * If not -1, then ch1 will point to:
12042 * 1) For predicates (XPATH_OP_PREDICATE):
12043 * - an inner predicate operator
12044 * 2) For filters (XPATH_OP_FILTER):
12045 * - an inner filter operater OR
12046 * - an expression selecting the node set.
12047 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012048 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012049 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12050 return(0);
12051
12052 if (op->ch2 != -1) {
12053 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012054 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012055 return(0);
12056
12057 if ((exprOp != NULL) &&
12058 (exprOp->op == XPATH_OP_VALUE) &&
12059 (exprOp->value4 != NULL) &&
12060 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12061 {
Nick Wellnhofera58331a2017-05-29 21:02:21 +020012062 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12063
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012064 /*
12065 * We have a "[n]" predicate here.
12066 * TODO: Unfortunately this simplistic test here is not
12067 * able to detect a position() predicate in compound
12068 * expressions like "[@attr = 'a" and position() = 1],
12069 * and even not the usage of position() in
12070 * "[position() = 1]"; thus - obviously - a position-range,
12071 * like it "[position() < 5]", is also not detected.
12072 * Maybe we could rewrite the AST to ease the optimization.
12073 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012074
Nick Wellnhofera58331a2017-05-29 21:02:21 +020012075 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12076 *maxPos = (int) floatval;
12077 if (floatval == (double) *maxPos)
12078 return(1);
12079 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012080 }
12081 return(0);
12082}
12083
12084static int
12085xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12086 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012087 xmlNodePtr * first, xmlNodePtr * last,
12088 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012089{
12090
12091#define XP_TEST_HIT \
12092 if (hasAxisRange != 0) { \
12093 if (++pos == maxPos) { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012094 if (addNode(seq, cur) < 0) \
12095 ctxt->error = XPATH_MEMORY_ERROR; \
12096 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012097 } else { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012098 if (addNode(seq, cur) < 0) \
12099 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012100 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012101
12102#define XP_TEST_HIT_NS \
12103 if (hasAxisRange != 0) { \
12104 if (++pos == maxPos) { \
12105 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012106 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12107 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012108 goto axis_range_end; } \
12109 } else { \
12110 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012111 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12112 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012113 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012114
12115 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12116 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12117 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12118 const xmlChar *prefix = op->value4;
12119 const xmlChar *name = op->value5;
12120 const xmlChar *URI = NULL;
12121
12122#ifdef DEBUG_STEP
12123 int nbMatches = 0, prevMatches = 0;
12124#endif
12125 int total = 0, hasNsNodes = 0;
12126 /* The popped object holding the context nodes */
12127 xmlXPathObjectPtr obj;
12128 /* The set of context nodes for the node tests */
12129 xmlNodeSetPtr contextSeq;
12130 int contextIdx;
12131 xmlNodePtr contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012132 /* The final resulting node set wrt to all context nodes */
12133 xmlNodeSetPtr outSeq;
12134 /*
12135 * The temporary resulting node set wrt 1 context node.
12136 * Used to feed predicate evaluation.
12137 */
12138 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012139 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012140 /* First predicate operator */
12141 xmlXPathStepOpPtr predOp;
12142 int maxPos; /* The requested position() (when a "[n]" predicate) */
12143 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012144 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012145
12146 xmlXPathTraversalFunction next = NULL;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012147 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012148 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012149 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012150 xmlXPathContextPtr xpctxt = ctxt->context;
12151
12152
12153 CHECK_TYPE0(XPATH_NODESET);
12154 obj = valuePop(ctxt);
12155 /*
12156 * Setup namespaces.
12157 */
12158 if (prefix != NULL) {
12159 URI = xmlXPathNsLookup(xpctxt, prefix);
12160 if (URI == NULL) {
12161 xmlXPathReleaseObject(xpctxt, obj);
12162 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12163 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012164 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012165 /*
12166 * Setup axis.
12167 *
12168 * MAYBE FUTURE TODO: merging optimizations:
12169 * - If the nodes to be traversed wrt to the initial nodes and
12170 * the current axis cannot overlap, then we could avoid searching
12171 * for duplicates during the merge.
12172 * But the question is how/when to evaluate if they cannot overlap.
12173 * Example: if we know that for two initial nodes, the one is
12174 * not in the ancestor-or-self axis of the other, then we could safely
12175 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12176 * the descendant-or-self axis.
12177 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012178 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12179 switch (axis) {
12180 case AXIS_ANCESTOR:
12181 first = NULL;
12182 next = xmlXPathNextAncestor;
12183 break;
12184 case AXIS_ANCESTOR_OR_SELF:
12185 first = NULL;
12186 next = xmlXPathNextAncestorOrSelf;
12187 break;
12188 case AXIS_ATTRIBUTE:
12189 first = NULL;
12190 last = NULL;
12191 next = xmlXPathNextAttribute;
12192 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12193 break;
12194 case AXIS_CHILD:
12195 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012196 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12197 (type == NODE_TYPE_NODE))
12198 {
12199 /*
12200 * Optimization if an element node type is 'element'.
12201 */
12202 next = xmlXPathNextChildElement;
12203 } else
12204 next = xmlXPathNextChild;
12205 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12206 break;
12207 case AXIS_DESCENDANT:
12208 last = NULL;
12209 next = xmlXPathNextDescendant;
12210 break;
12211 case AXIS_DESCENDANT_OR_SELF:
12212 last = NULL;
12213 next = xmlXPathNextDescendantOrSelf;
12214 break;
12215 case AXIS_FOLLOWING:
12216 last = NULL;
12217 next = xmlXPathNextFollowing;
12218 break;
12219 case AXIS_FOLLOWING_SIBLING:
12220 last = NULL;
12221 next = xmlXPathNextFollowingSibling;
12222 break;
12223 case AXIS_NAMESPACE:
12224 first = NULL;
12225 last = NULL;
12226 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12227 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12228 break;
12229 case AXIS_PARENT:
12230 first = NULL;
12231 next = xmlXPathNextParent;
12232 break;
12233 case AXIS_PRECEDING:
12234 first = NULL;
12235 next = xmlXPathNextPrecedingInternal;
12236 break;
12237 case AXIS_PRECEDING_SIBLING:
12238 first = NULL;
12239 next = xmlXPathNextPrecedingSibling;
12240 break;
12241 case AXIS_SELF:
12242 first = NULL;
12243 last = NULL;
12244 next = xmlXPathNextSelf;
12245 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12246 break;
12247 }
12248
12249#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012250 xmlXPathDebugDumpStepAxis(op,
12251 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012252#endif
12253
12254 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012255 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012256 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012257 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012258 contextSeq = obj->nodesetval;
12259 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12260 xmlXPathReleaseObject(xpctxt, obj);
12261 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12262 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012263 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012264 /*
12265 * Predicate optimization ---------------------------------------------
12266 * If this step has a last predicate, which contains a position(),
12267 * then we'll optimize (although not exactly "position()", but only
12268 * the short-hand form, i.e., "[n]".
12269 *
12270 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012271 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012272 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12273 * ROOT -- op->ch1
12274 * PREDICATE -- op->ch2 (predOp)
12275 * PREDICATE -- predOp->ch1 = [parent::bar]
12276 * SORT
12277 * COLLECT 'parent' 'name' 'node' bar
12278 * NODE
12279 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12280 *
12281 */
12282 maxPos = 0;
12283 predOp = NULL;
12284 hasPredicateRange = 0;
12285 hasAxisRange = 0;
12286 if (op->ch2 != -1) {
12287 /*
12288 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12289 */
12290 predOp = &ctxt->comp->steps[op->ch2];
12291 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12292 if (predOp->ch1 != -1) {
12293 /*
12294 * Use the next inner predicate operator.
12295 */
12296 predOp = &ctxt->comp->steps[predOp->ch1];
12297 hasPredicateRange = 1;
12298 } else {
12299 /*
12300 * There's no other predicate than the [n] predicate.
12301 */
12302 predOp = NULL;
12303 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012304 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012305 }
12306 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012307 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012308 /*
12309 * Axis traversal -----------------------------------------------------
12310 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012311 /*
12312 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012313 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012314 * - For the namespace axis, the principal node type is namespace.
12315 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012316 *
12317 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012318 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012319 * select all element children of the context node
12320 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012321 oldContextNode = xpctxt->node;
12322 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012323 outSeq = NULL;
12324 seq = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012325 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012326 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012327
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012328
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012329 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12330 (ctxt->error == XPATH_EXPRESSION_OK)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012331 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012332
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012333 if (seq == NULL) {
12334 seq = xmlXPathNodeSetCreate(NULL);
12335 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012336 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012337 goto error;
12338 }
12339 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012340 /*
12341 * Traverse the axis and test the nodes.
12342 */
12343 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012344 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012345 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012346 do {
12347 cur = next(ctxt, cur);
12348 if (cur == NULL)
12349 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012350
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012351 /*
12352 * QUESTION TODO: What does the "first" and "last" stuff do?
12353 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012354 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012355 if (*first == cur)
12356 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012357 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012358#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012359 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012360#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012361 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012362#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012363 {
12364 break;
12365 }
12366 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012367 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012368 if (*last == cur)
12369 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012370 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012371#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012372 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012373#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012374 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012375#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012376 {
12377 break;
12378 }
12379 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012380
12381 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012382
Daniel Veillardf06307e2001-07-03 10:35:50 +000012383#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012384 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12385#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012386
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012387 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012388 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012389 total = 0;
12390 STRANGE
12391 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012392 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012393 if (type == NODE_TYPE_NODE) {
12394 switch (cur->type) {
12395 case XML_DOCUMENT_NODE:
12396 case XML_HTML_DOCUMENT_NODE:
12397#ifdef LIBXML_DOCB_ENABLED
12398 case XML_DOCB_DOCUMENT_NODE:
12399#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012400 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012401 case XML_ATTRIBUTE_NODE:
12402 case XML_PI_NODE:
12403 case XML_COMMENT_NODE:
12404 case XML_CDATA_SECTION_NODE:
12405 case XML_TEXT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012406 XP_TEST_HIT
12407 break;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012408 case XML_NAMESPACE_DECL: {
12409 if (axis == AXIS_NAMESPACE) {
12410 XP_TEST_HIT_NS
12411 } else {
Nick Wellnhofer6eb08942016-05-05 16:49:00 +020012412 hasNsNodes = 1;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012413 XP_TEST_HIT
12414 }
12415 break;
12416 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012417 default:
12418 break;
12419 }
12420 } else if (cur->type == type) {
Daniel Veillard713434d2012-09-26 10:21:06 +080012421 if (cur->type == XML_NAMESPACE_DECL)
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012422 XP_TEST_HIT_NS
12423 else
12424 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012425 } else if ((type == NODE_TYPE_TEXT) &&
12426 (cur->type == XML_CDATA_SECTION_NODE))
12427 {
12428 XP_TEST_HIT
12429 }
12430 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012431 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012432 if ((cur->type == XML_PI_NODE) &&
12433 ((name == NULL) || xmlStrEqual(name, cur->name)))
12434 {
12435 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012436 }
12437 break;
12438 case NODE_TEST_ALL:
12439 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012440 if (cur->type == XML_ATTRIBUTE_NODE)
12441 {
Nick Wellnhofere8de99f2013-08-05 01:26:25 +020012442 if (prefix == NULL)
12443 {
12444 XP_TEST_HIT
12445 } else if ((cur->ns != NULL) &&
12446 (xmlStrEqual(URI, cur->ns->href)))
12447 {
12448 XP_TEST_HIT
12449 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012450 }
12451 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012452 if (cur->type == XML_NAMESPACE_DECL)
12453 {
12454 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012455 }
12456 } else {
12457 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012458 if (prefix == NULL)
12459 {
12460 XP_TEST_HIT
12461
Daniel Veillardf06307e2001-07-03 10:35:50 +000012462 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012463 (xmlStrEqual(URI, cur->ns->href)))
12464 {
12465 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012466 }
12467 }
12468 }
12469 break;
12470 case NODE_TEST_NS:{
12471 TODO;
12472 break;
12473 }
12474 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012475 if (axis == AXIS_ATTRIBUTE) {
12476 if (cur->type != XML_ATTRIBUTE_NODE)
12477 break;
12478 } else if (axis == AXIS_NAMESPACE) {
12479 if (cur->type != XML_NAMESPACE_DECL)
12480 break;
12481 } else {
12482 if (cur->type != XML_ELEMENT_NODE)
12483 break;
12484 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012485 switch (cur->type) {
12486 case XML_ELEMENT_NODE:
12487 if (xmlStrEqual(name, cur->name)) {
12488 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012489 if (cur->ns == NULL)
12490 {
12491 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012492 }
12493 } else {
12494 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012495 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012496 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012497 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012498 }
12499 }
12500 }
12501 break;
12502 case XML_ATTRIBUTE_NODE:{
12503 xmlAttrPtr attr = (xmlAttrPtr) cur;
12504
12505 if (xmlStrEqual(name, attr->name)) {
12506 if (prefix == NULL) {
12507 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012508 (attr->ns->prefix == NULL))
12509 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012510 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012511 }
12512 } else {
12513 if ((attr->ns != NULL) &&
12514 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012515 attr->ns->href)))
12516 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012517 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012518 }
12519 }
12520 }
12521 break;
12522 }
12523 case XML_NAMESPACE_DECL:
12524 if (cur->type == XML_NAMESPACE_DECL) {
12525 xmlNsPtr ns = (xmlNsPtr) cur;
12526
12527 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012528 && (xmlStrEqual(ns->prefix, name)))
12529 {
12530 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012531 }
12532 }
12533 break;
12534 default:
12535 break;
12536 }
12537 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012538 } /* switch(test) */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012539 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012540
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012541 goto apply_predicates;
12542
Daniel Veillard45490ae2008-07-29 09:13:19 +000012543axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012544 /*
12545 * We have a "/foo[n]", and position() = n was reached.
12546 * Note that we can have as well "/foo/::parent::foo[1]", so
12547 * a duplicate-aware merge is still needed.
12548 * Merge with the result.
12549 */
12550 if (outSeq == NULL) {
12551 outSeq = seq;
12552 seq = NULL;
12553 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012554 outSeq = mergeAndClear(outSeq, seq, 0);
12555 /*
12556 * Break if only a true/false result was requested.
12557 */
12558 if (toBool)
12559 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012560 continue;
12561
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012562first_hit: /* ---------------------------------------------------------- */
12563 /*
12564 * Break if only a true/false result was requested and
12565 * no predicates existed and a node test succeeded.
12566 */
12567 if (outSeq == NULL) {
12568 outSeq = seq;
12569 seq = NULL;
12570 } else
12571 outSeq = mergeAndClear(outSeq, seq, 0);
12572 break;
12573
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012574#ifdef DEBUG_STEP
12575 if (seq != NULL)
12576 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012577#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012578
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012579apply_predicates: /* --------------------------------------------------- */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012580 if (ctxt->error != XPATH_EXPRESSION_OK)
12581 goto error;
12582
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012583 /*
12584 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012585 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012586 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12587 /*
12588 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012589 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012590 /*
12591 * QUESTION TODO: The old predicate evaluation took into
12592 * account location-sets.
12593 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12594 * Do we expect such a set here?
12595 * All what I learned now from the evaluation semantics
12596 * does not indicate that a location-set will be processed
12597 * here, so this looks OK.
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012598 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012599 /*
12600 * Iterate over all predicates, starting with the outermost
12601 * predicate.
12602 * TODO: Problem: we cannot execute the inner predicates first
12603 * since we cannot go back *up* the operator tree!
12604 * Options we have:
12605 * 1) Use of recursive functions (like is it currently done
12606 * via xmlXPathCompOpEval())
12607 * 2) Add a predicate evaluation information stack to the
12608 * context struct
12609 * 3) Change the way the operators are linked; we need a
12610 * "parent" field on xmlXPathStepOp
12611 *
12612 * For the moment, I'll try to solve this with a recursive
12613 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012614 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012615 size = seq->nodeNr;
12616 if (hasPredicateRange != 0)
12617 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12618 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12619 else
12620 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12621 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012622
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012623 if (ctxt->error != XPATH_EXPRESSION_OK) {
12624 total = 0;
12625 goto error;
12626 }
12627 /*
12628 * Add the filtered set of nodes to the result node set.
12629 */
12630 if (newSize == 0) {
12631 /*
12632 * The predicates filtered all nodes out.
12633 */
12634 xmlXPathNodeSetClear(seq, hasNsNodes);
12635 } else if (seq->nodeNr > 0) {
12636 /*
12637 * Add to result set.
12638 */
12639 if (outSeq == NULL) {
12640 if (size != newSize) {
12641 /*
12642 * We need to merge and clear here, since
12643 * the sequence will contained NULLed entries.
12644 */
12645 outSeq = mergeAndClear(NULL, seq, 1);
12646 } else {
12647 outSeq = seq;
12648 seq = NULL;
12649 }
12650 } else
12651 outSeq = mergeAndClear(outSeq, seq,
12652 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012653 /*
12654 * Break if only a true/false result was requested.
12655 */
12656 if (toBool)
12657 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012658 }
12659 } else if (seq->nodeNr > 0) {
12660 /*
12661 * Add to result set.
12662 */
12663 if (outSeq == NULL) {
12664 outSeq = seq;
12665 seq = NULL;
12666 } else {
12667 outSeq = mergeAndClear(outSeq, seq, 0);
12668 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012669 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012670 }
12671
12672error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012673 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012674 /*
12675 * QUESTION TODO: What does this do and why?
12676 * TODO: Do we have to do this also for the "error"
12677 * cleanup further down?
12678 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012679 ctxt->value->boolval = 1;
12680 ctxt->value->user = obj->user;
12681 obj->user = NULL;
12682 obj->boolval = 0;
12683 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012684 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012685
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012686 /*
12687 * Ensure we return at least an emtpy set.
12688 */
12689 if (outSeq == NULL) {
12690 if ((seq != NULL) && (seq->nodeNr == 0))
12691 outSeq = seq;
12692 else
12693 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012694 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012695 }
12696 if ((seq != NULL) && (seq != outSeq)) {
12697 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012698 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012699 /*
12700 * Hand over the result. Better to push the set also in
12701 * case of errors.
12702 */
12703 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12704 /*
12705 * Reset the context node.
12706 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012707 xpctxt->node = oldContextNode;
Nick Wellnhofer82b73032016-04-30 17:53:10 +020012708 /*
12709 * When traversing the namespace axis in "toBool" mode, it's
12710 * possible that tmpNsList wasn't freed.
12711 */
12712 if (xpctxt->tmpNsList != NULL) {
12713 xmlFree(xpctxt->tmpNsList);
12714 xpctxt->tmpNsList = NULL;
12715 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012716
12717#ifdef DEBUG_STEP
12718 xmlGenericError(xmlGenericErrorContext,
12719 "\nExamined %d nodes, found %d nodes at that step\n",
12720 total, nbMatches);
12721#endif
12722
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012723 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012724}
12725
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012726static int
12727xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12728 xmlXPathStepOpPtr op, xmlNodePtr * first);
12729
Daniel Veillardf06307e2001-07-03 10:35:50 +000012730/**
12731 * xmlXPathCompOpEvalFirst:
12732 * @ctxt: the XPath parser context with the compiled expression
12733 * @op: an XPath compiled operation
12734 * @first: the first elem found so far
12735 *
12736 * Evaluate the Precompiled XPath operation searching only the first
12737 * element in document order
12738 *
12739 * Returns the number of examined objects.
12740 */
12741static int
12742xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12743 xmlXPathStepOpPtr op, xmlNodePtr * first)
12744{
12745 int total = 0, cur;
12746 xmlXPathCompExprPtr comp;
12747 xmlXPathObjectPtr arg1, arg2;
12748
Daniel Veillard556c6682001-10-06 09:59:51 +000012749 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012750 comp = ctxt->comp;
12751 switch (op->op) {
12752 case XPATH_OP_END:
12753 return (0);
12754 case XPATH_OP_UNION:
12755 total =
12756 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12757 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012758 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012759 if ((ctxt->value != NULL)
12760 && (ctxt->value->type == XPATH_NODESET)
12761 && (ctxt->value->nodesetval != NULL)
12762 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12763 /*
12764 * limit tree traversing to first node in the result
12765 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012766 /*
12767 * OPTIMIZE TODO: This implicitely sorts
12768 * the result, even if not needed. E.g. if the argument
12769 * of the count() function, no sorting is needed.
12770 * OPTIMIZE TODO: How do we know if the node-list wasn't
12771 * aready sorted?
12772 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012773 if (ctxt->value->nodesetval->nodeNr > 1)
12774 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012775 *first = ctxt->value->nodesetval->nodeTab[0];
12776 }
12777 cur =
12778 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12779 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012780 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012781
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012782 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012783 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012784 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12785 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12786 xmlXPathReleaseObject(ctxt->context, arg1);
12787 xmlXPathReleaseObject(ctxt->context, arg2);
12788 XP_ERROR0(XPATH_INVALID_TYPE);
12789 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012790
12791 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12792 arg2->nodesetval);
12793 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012794 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012795 /* optimizer */
12796 if (total > cur)
12797 xmlXPathCompSwap(op);
12798 return (total + cur);
12799 case XPATH_OP_ROOT:
12800 xmlXPathRoot(ctxt);
12801 return (0);
12802 case XPATH_OP_NODE:
12803 if (op->ch1 != -1)
12804 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012805 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012806 if (op->ch2 != -1)
12807 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012808 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012809 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12810 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012811 return (total);
12812 case XPATH_OP_RESET:
12813 if (op->ch1 != -1)
12814 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012815 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012816 if (op->ch2 != -1)
12817 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012818 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012819 ctxt->context->node = NULL;
12820 return (total);
12821 case XPATH_OP_COLLECT:{
12822 if (op->ch1 == -1)
12823 return (total);
12824
12825 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012826 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012827
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012828 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012829 return (total);
12830 }
12831 case XPATH_OP_VALUE:
12832 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012833 xmlXPathCacheObjectCopy(ctxt->context,
12834 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012835 return (0);
12836 case XPATH_OP_SORT:
12837 if (op->ch1 != -1)
12838 total +=
12839 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12840 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012841 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012842 if ((ctxt->value != NULL)
12843 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012844 && (ctxt->value->nodesetval != NULL)
12845 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012846 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12847 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012848#ifdef XP_OPTIMIZED_FILTER_FIRST
12849 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012850 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012851 return (total);
12852#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012853 default:
12854 return (xmlXPathCompOpEval(ctxt, op));
12855 }
12856}
12857
12858/**
12859 * xmlXPathCompOpEvalLast:
12860 * @ctxt: the XPath parser context with the compiled expression
12861 * @op: an XPath compiled operation
12862 * @last: the last elem found so far
12863 *
12864 * Evaluate the Precompiled XPath operation searching only the last
12865 * element in document order
12866 *
William M. Brack08171912003-12-29 02:52:11 +000012867 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012868 */
12869static int
12870xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12871 xmlNodePtr * last)
12872{
12873 int total = 0, cur;
12874 xmlXPathCompExprPtr comp;
12875 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012876 xmlNodePtr bak;
12877 xmlDocPtr bakd;
12878 int pp;
12879 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012880
Daniel Veillard556c6682001-10-06 09:59:51 +000012881 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012882 comp = ctxt->comp;
12883 switch (op->op) {
12884 case XPATH_OP_END:
12885 return (0);
12886 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012887 bakd = ctxt->context->doc;
12888 bak = ctxt->context->node;
12889 pp = ctxt->context->proximityPosition;
12890 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012891 total =
12892 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012893 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012894 if ((ctxt->value != NULL)
12895 && (ctxt->value->type == XPATH_NODESET)
12896 && (ctxt->value->nodesetval != NULL)
12897 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12898 /*
12899 * limit tree traversing to first node in the result
12900 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012901 if (ctxt->value->nodesetval->nodeNr > 1)
12902 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012903 *last =
12904 ctxt->value->nodesetval->nodeTab[ctxt->value->
12905 nodesetval->nodeNr -
12906 1];
12907 }
William M. Brackce4fc562004-01-22 02:47:18 +000012908 ctxt->context->doc = bakd;
12909 ctxt->context->node = bak;
12910 ctxt->context->proximityPosition = pp;
12911 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012912 cur =
12913 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012914 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012915 if ((ctxt->value != NULL)
12916 && (ctxt->value->type == XPATH_NODESET)
12917 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012918 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012919 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012920
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012921 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012922 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012923 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12924 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12925 xmlXPathReleaseObject(ctxt->context, arg1);
12926 xmlXPathReleaseObject(ctxt->context, arg2);
12927 XP_ERROR0(XPATH_INVALID_TYPE);
12928 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012929
12930 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12931 arg2->nodesetval);
12932 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012933 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012934 /* optimizer */
12935 if (total > cur)
12936 xmlXPathCompSwap(op);
12937 return (total + cur);
12938 case XPATH_OP_ROOT:
12939 xmlXPathRoot(ctxt);
12940 return (0);
12941 case XPATH_OP_NODE:
12942 if (op->ch1 != -1)
12943 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012944 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012945 if (op->ch2 != -1)
12946 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012947 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012948 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12949 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012950 return (total);
12951 case XPATH_OP_RESET:
12952 if (op->ch1 != -1)
12953 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012954 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012955 if (op->ch2 != -1)
12956 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012957 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012958 ctxt->context->node = NULL;
12959 return (total);
12960 case XPATH_OP_COLLECT:{
12961 if (op->ch1 == -1)
12962 return (0);
12963
12964 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012965 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012966
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012967 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012968 return (total);
12969 }
12970 case XPATH_OP_VALUE:
12971 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012972 xmlXPathCacheObjectCopy(ctxt->context,
12973 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012974 return (0);
12975 case XPATH_OP_SORT:
12976 if (op->ch1 != -1)
12977 total +=
12978 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12979 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012980 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012981 if ((ctxt->value != NULL)
12982 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012983 && (ctxt->value->nodesetval != NULL)
12984 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012985 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12986 return (total);
12987 default:
12988 return (xmlXPathCompOpEval(ctxt, op));
12989 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012990}
12991
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012992#ifdef XP_OPTIMIZED_FILTER_FIRST
12993static int
12994xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12995 xmlXPathStepOpPtr op, xmlNodePtr * first)
12996{
12997 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012998 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012999 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013000 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013001 xmlNodeSetPtr oldset;
13002 xmlNodePtr oldnode;
13003 xmlDocPtr oldDoc;
13004 int i;
13005
13006 CHECK_ERROR0;
13007 comp = ctxt->comp;
13008 /*
13009 * Optimization for ()[last()] selection i.e. the last elem
13010 */
13011 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13012 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13013 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13014 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013015
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013016 if ((f != -1) &&
13017 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13018 (comp->steps[f].value5 == NULL) &&
13019 (comp->steps[f].value == 0) &&
13020 (comp->steps[f].value4 != NULL) &&
13021 (xmlStrEqual
13022 (comp->steps[f].value4, BAD_CAST "last"))) {
13023 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013024
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013025 total +=
13026 xmlXPathCompOpEvalLast(ctxt,
13027 &comp->steps[op->ch1],
13028 &last);
13029 CHECK_ERROR0;
13030 /*
13031 * The nodeset should be in document order,
13032 * Keep only the last value
13033 */
13034 if ((ctxt->value != NULL) &&
13035 (ctxt->value->type == XPATH_NODESET) &&
13036 (ctxt->value->nodesetval != NULL) &&
13037 (ctxt->value->nodesetval->nodeTab != NULL) &&
13038 (ctxt->value->nodesetval->nodeNr > 1)) {
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013039 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013040 *first = *(ctxt->value->nodesetval->nodeTab);
13041 }
13042 return (total);
13043 }
13044 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013045
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013046 if (op->ch1 != -1)
13047 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13048 CHECK_ERROR0;
13049 if (op->ch2 == -1)
13050 return (total);
13051 if (ctxt->value == NULL)
13052 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013053
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013054#ifdef LIBXML_XPTR_ENABLED
13055 oldnode = ctxt->context->node;
13056 /*
13057 * Hum are we filtering the result of an XPointer expression
13058 */
13059 if (ctxt->value->type == XPATH_LOCATIONSET) {
13060 xmlXPathObjectPtr tmp = NULL;
13061 xmlLocationSetPtr newlocset = NULL;
13062 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013063
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013064 /*
13065 * Extract the old locset, and then evaluate the result of the
13066 * expression for all the element in the locset. use it to grow
13067 * up a new locset.
13068 */
13069 CHECK_TYPE0(XPATH_LOCATIONSET);
13070 obj = valuePop(ctxt);
13071 oldlocset = obj->user;
13072 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013073
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013074 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13075 ctxt->context->contextSize = 0;
13076 ctxt->context->proximityPosition = 0;
13077 if (op->ch2 != -1)
13078 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13079 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013080 if (res != NULL) {
13081 xmlXPathReleaseObject(ctxt->context, res);
13082 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013083 valuePush(ctxt, obj);
13084 CHECK_ERROR0;
13085 return (total);
13086 }
13087 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013088
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013089 for (i = 0; i < oldlocset->locNr; i++) {
13090 /*
13091 * Run the evaluation with a node list made of a
13092 * single item in the nodelocset.
13093 */
13094 ctxt->context->node = oldlocset->locTab[i]->user;
13095 ctxt->context->contextSize = oldlocset->locNr;
13096 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013097 if (tmp == NULL) {
13098 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13099 ctxt->context->node);
13100 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013101 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13102 ctxt->context->node) < 0) {
13103 ctxt->error = XPATH_MEMORY_ERROR;
13104 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013105 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013106 valuePush(ctxt, tmp);
13107 if (op->ch2 != -1)
13108 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13109 if (ctxt->error != XPATH_EXPRESSION_OK) {
13110 xmlXPathFreeObject(obj);
13111 return(0);
13112 }
13113 /*
13114 * The result of the evaluation need to be tested to
13115 * decided whether the filter succeeded or not
13116 */
13117 res = valuePop(ctxt);
13118 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13119 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013120 xmlXPathCacheObjectCopy(ctxt->context,
13121 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013122 }
13123 /*
13124 * Cleanup
13125 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013126 if (res != NULL) {
13127 xmlXPathReleaseObject(ctxt->context, res);
13128 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013129 if (ctxt->value == tmp) {
13130 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013131 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013132 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013133 * REVISIT TODO: Don't create a temporary nodeset
13134 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013135 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013136 /* OLD: xmlXPathFreeObject(res); */
13137 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013138 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013139 ctxt->context->node = NULL;
13140 /*
13141 * Only put the first node in the result, then leave.
13142 */
13143 if (newlocset->locNr > 0) {
13144 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13145 break;
13146 }
13147 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013148 if (tmp != NULL) {
13149 xmlXPathReleaseObject(ctxt->context, tmp);
13150 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013151 /*
13152 * The result is used as the new evaluation locset.
13153 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013154 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013155 ctxt->context->node = NULL;
13156 ctxt->context->contextSize = -1;
13157 ctxt->context->proximityPosition = -1;
13158 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13159 ctxt->context->node = oldnode;
13160 return (total);
13161 }
13162#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013163
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013164 /*
13165 * Extract the old set, and then evaluate the result of the
13166 * expression for all the element in the set. use it to grow
13167 * up a new set.
13168 */
13169 CHECK_TYPE0(XPATH_NODESET);
13170 obj = valuePop(ctxt);
13171 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013172
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013173 oldnode = ctxt->context->node;
13174 oldDoc = ctxt->context->doc;
13175 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013176
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013177 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13178 ctxt->context->contextSize = 0;
13179 ctxt->context->proximityPosition = 0;
13180 /* QUESTION TODO: Why was this code commented out?
13181 if (op->ch2 != -1)
13182 total +=
13183 xmlXPathCompOpEval(ctxt,
13184 &comp->steps[op->ch2]);
13185 CHECK_ERROR0;
13186 res = valuePop(ctxt);
13187 if (res != NULL)
13188 xmlXPathFreeObject(res);
13189 */
13190 valuePush(ctxt, obj);
13191 ctxt->context->node = oldnode;
13192 CHECK_ERROR0;
13193 } else {
13194 xmlNodeSetPtr newset;
13195 xmlXPathObjectPtr tmp = NULL;
13196 /*
13197 * Initialize the new set.
13198 * Also set the xpath document in case things like
13199 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013200 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013201 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013202 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013203
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013204 for (i = 0; i < oldset->nodeNr; i++) {
13205 /*
13206 * Run the evaluation with a node list made of
13207 * a single item in the nodeset.
13208 */
13209 ctxt->context->node = oldset->nodeTab[i];
13210 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13211 (oldset->nodeTab[i]->doc != NULL))
13212 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013213 if (tmp == NULL) {
13214 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13215 ctxt->context->node);
13216 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013217 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13218 ctxt->context->node) < 0) {
13219 ctxt->error = XPATH_MEMORY_ERROR;
13220 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013221 }
13222 valuePush(ctxt, tmp);
13223 ctxt->context->contextSize = oldset->nodeNr;
13224 ctxt->context->proximityPosition = i + 1;
13225 if (op->ch2 != -1)
13226 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13227 if (ctxt->error != XPATH_EXPRESSION_OK) {
13228 xmlXPathFreeNodeSet(newset);
13229 xmlXPathFreeObject(obj);
13230 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013231 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013232 /*
13233 * The result of the evaluation needs to be tested to
13234 * decide whether the filter succeeded or not
13235 */
13236 res = valuePop(ctxt);
13237 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013238 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13239 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013240 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013241 /*
13242 * Cleanup
13243 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013244 if (res != NULL) {
13245 xmlXPathReleaseObject(ctxt->context, res);
13246 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013247 if (ctxt->value == tmp) {
13248 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013249 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013250 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013251 * in order to avoid massive recreation inside this
13252 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013253 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013254 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013255 } else
13256 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013257 ctxt->context->node = NULL;
13258 /*
13259 * Only put the first node in the result, then leave.
13260 */
13261 if (newset->nodeNr > 0) {
13262 *first = *(newset->nodeTab);
13263 break;
13264 }
13265 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013266 if (tmp != NULL) {
13267 xmlXPathReleaseObject(ctxt->context, tmp);
13268 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013269 /*
13270 * The result is used as the new evaluation set.
13271 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013272 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013273 ctxt->context->node = NULL;
13274 ctxt->context->contextSize = -1;
13275 ctxt->context->proximityPosition = -1;
13276 /* may want to move this past the '}' later */
13277 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013278 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013279 }
13280 ctxt->context->node = oldnode;
13281 return(total);
13282}
13283#endif /* XP_OPTIMIZED_FILTER_FIRST */
13284
Owen Taylor3473f882001-02-23 17:55:21 +000013285/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013286 * xmlXPathCompOpEval:
13287 * @ctxt: the XPath parser context with the compiled expression
13288 * @op: an XPath compiled operation
13289 *
13290 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013291 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013292 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013293static int
13294xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13295{
13296 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013297 int equal, ret;
13298 xmlXPathCompExprPtr comp;
13299 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013300 xmlNodePtr bak;
13301 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013302 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013303 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013304
Daniel Veillard556c6682001-10-06 09:59:51 +000013305 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013306 comp = ctxt->comp;
13307 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013308 case XPATH_OP_END:
13309 return (0);
13310 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013311 bakd = ctxt->context->doc;
13312 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013313 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013314 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013315 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013316 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013317 xmlXPathBooleanFunction(ctxt, 1);
13318 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13319 return (total);
13320 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013321 ctxt->context->doc = bakd;
13322 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013323 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013324 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013325 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013326 if (ctxt->error) {
13327 xmlXPathFreeObject(arg2);
13328 return(0);
13329 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013330 xmlXPathBooleanFunction(ctxt, 1);
13331 arg1 = valuePop(ctxt);
13332 arg1->boolval &= arg2->boolval;
13333 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013334 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013335 return (total);
13336 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013337 bakd = ctxt->context->doc;
13338 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013339 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013340 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013341 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013342 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013343 xmlXPathBooleanFunction(ctxt, 1);
13344 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13345 return (total);
13346 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013347 ctxt->context->doc = bakd;
13348 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013349 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013350 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013351 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013352 if (ctxt->error) {
13353 xmlXPathFreeObject(arg2);
13354 return(0);
13355 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013356 xmlXPathBooleanFunction(ctxt, 1);
13357 arg1 = valuePop(ctxt);
13358 arg1->boolval |= arg2->boolval;
13359 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013360 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013361 return (total);
13362 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013363 bakd = ctxt->context->doc;
13364 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013365 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013366 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013367 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013368 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013369 ctxt->context->doc = bakd;
13370 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013371 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013372 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013373 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013374 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013375 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013376 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013377 else
13378 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013379 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013380 return (total);
13381 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013382 bakd = ctxt->context->doc;
13383 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013384 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013385 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013386 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013387 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013388 ctxt->context->doc = bakd;
13389 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013390 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013391 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013392 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013393 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013394 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013395 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013396 return (total);
13397 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013398 bakd = ctxt->context->doc;
13399 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013400 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013401 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013402 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013403 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013404 if (op->ch2 != -1) {
13405 ctxt->context->doc = bakd;
13406 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013407 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013408 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013409 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013410 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013411 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013412 if (op->value == 0)
13413 xmlXPathSubValues(ctxt);
13414 else if (op->value == 1)
13415 xmlXPathAddValues(ctxt);
13416 else if (op->value == 2)
13417 xmlXPathValueFlipSign(ctxt);
13418 else if (op->value == 3) {
13419 CAST_TO_NUMBER;
13420 CHECK_TYPE0(XPATH_NUMBER);
13421 }
13422 return (total);
13423 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013424 bakd = ctxt->context->doc;
13425 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013426 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013427 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013428 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013429 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013430 ctxt->context->doc = bakd;
13431 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013432 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013433 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013434 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013435 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013436 if (op->value == 0)
13437 xmlXPathMultValues(ctxt);
13438 else if (op->value == 1)
13439 xmlXPathDivValues(ctxt);
13440 else if (op->value == 2)
13441 xmlXPathModValues(ctxt);
13442 return (total);
13443 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013444 bakd = ctxt->context->doc;
13445 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013446 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013447 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013448 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013449 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013450 ctxt->context->doc = bakd;
13451 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013452 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013453 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013454 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013455 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013456
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013457 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013458 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013459 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13460 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13461 xmlXPathReleaseObject(ctxt->context, arg1);
13462 xmlXPathReleaseObject(ctxt->context, arg2);
13463 XP_ERROR0(XPATH_INVALID_TYPE);
13464 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013465
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013466 if ((arg1->nodesetval == NULL) ||
13467 ((arg2->nodesetval != NULL) &&
13468 (arg2->nodesetval->nodeNr != 0)))
13469 {
13470 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13471 arg2->nodesetval);
13472 }
13473
Daniel Veillardf06307e2001-07-03 10:35:50 +000013474 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013475 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013476 return (total);
13477 case XPATH_OP_ROOT:
13478 xmlXPathRoot(ctxt);
13479 return (total);
13480 case XPATH_OP_NODE:
13481 if (op->ch1 != -1)
13482 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013483 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013484 if (op->ch2 != -1)
13485 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013486 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013487 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13488 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013489 return (total);
13490 case XPATH_OP_RESET:
13491 if (op->ch1 != -1)
13492 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013493 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013494 if (op->ch2 != -1)
13495 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013496 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013497 ctxt->context->node = NULL;
13498 return (total);
13499 case XPATH_OP_COLLECT:{
13500 if (op->ch1 == -1)
13501 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013502
Daniel Veillardf06307e2001-07-03 10:35:50 +000013503 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013504 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013505
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013506 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013507 return (total);
13508 }
13509 case XPATH_OP_VALUE:
13510 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013511 xmlXPathCacheObjectCopy(ctxt->context,
13512 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013513 return (total);
13514 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013515 xmlXPathObjectPtr val;
13516
Daniel Veillardf06307e2001-07-03 10:35:50 +000013517 if (op->ch1 != -1)
13518 total +=
13519 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013520 if (op->value5 == NULL) {
13521 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13522 if (val == NULL) {
13523 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13524 return(0);
13525 }
13526 valuePush(ctxt, val);
13527 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013528 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013529
Daniel Veillardf06307e2001-07-03 10:35:50 +000013530 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13531 if (URI == NULL) {
13532 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013533 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13534 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013535 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013536 return (total);
13537 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013538 val = xmlXPathVariableLookupNS(ctxt->context,
13539 op->value4, URI);
13540 if (val == NULL) {
13541 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13542 return(0);
13543 }
13544 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013545 }
13546 return (total);
13547 }
13548 case XPATH_OP_FUNCTION:{
13549 xmlXPathFunction func;
13550 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013551 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013552 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013553
Daniel Veillardf5048b32011-08-18 17:10:13 +080013554 frame = xmlXPathSetFrame(ctxt);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013555 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013556 total +=
13557 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013558 if (ctxt->error != XPATH_EXPRESSION_OK) {
13559 xmlXPathPopFrame(ctxt, frame);
13560 return (total);
13561 }
13562 }
13563 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013564 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013565 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013566 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013567 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013568 return (total);
13569 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013570 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013571 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13572 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013573 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013574 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013575 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013576 return (total);
13577 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013578 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013579 if (op->cache != NULL)
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013580 func = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013581 else {
13582 const xmlChar *URI = NULL;
13583
13584 if (op->value5 == NULL)
13585 func =
13586 xmlXPathFunctionLookup(ctxt->context,
13587 op->value4);
13588 else {
13589 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13590 if (URI == NULL) {
13591 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013592 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13593 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013594 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013595 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013596 return (total);
13597 }
13598 func = xmlXPathFunctionLookupNS(ctxt->context,
13599 op->value4, URI);
13600 }
13601 if (func == NULL) {
13602 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013603 "xmlXPathCompOpEval: function %s not found\n",
13604 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013605 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013606 }
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013607 op->cache = func;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013608 op->cacheURI = (void *) URI;
13609 }
13610 oldFunc = ctxt->context->function;
13611 oldFuncURI = ctxt->context->functionURI;
13612 ctxt->context->function = op->value4;
13613 ctxt->context->functionURI = op->cacheURI;
13614 func(ctxt, op->value);
13615 ctxt->context->function = oldFunc;
13616 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013617 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013618 return (total);
13619 }
13620 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013621 bakd = ctxt->context->doc;
13622 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013623 pp = ctxt->context->proximityPosition;
13624 cs = ctxt->context->contextSize;
Nick Wellnhofer07def302014-03-21 19:38:08 +010013625 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013626 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013627 ctxt->context->contextSize = cs;
13628 ctxt->context->proximityPosition = pp;
13629 ctxt->context->node = bak;
13630 ctxt->context->doc = bakd;
13631 CHECK_ERROR0;
13632 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013633 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013634 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013635 ctxt->context->contextSize = cs;
13636 ctxt->context->proximityPosition = pp;
13637 ctxt->context->node = bak;
13638 ctxt->context->doc = bakd;
William M. Brack72ee48d2003-12-30 08:30:19 +000013639 CHECK_ERROR0;
13640 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013641 return (total);
13642 case XPATH_OP_PREDICATE:
13643 case XPATH_OP_FILTER:{
13644 xmlXPathObjectPtr res;
13645 xmlXPathObjectPtr obj, tmp;
13646 xmlNodeSetPtr newset = NULL;
13647 xmlNodeSetPtr oldset;
13648 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013649 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013650 int i;
13651
13652 /*
13653 * Optimization for ()[1] selection i.e. the first elem
13654 */
13655 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013656#ifdef XP_OPTIMIZED_FILTER_FIRST
13657 /*
13658 * FILTER TODO: Can we assume that the inner processing
13659 * will result in an ordered list if we have an
13660 * XPATH_OP_FILTER?
13661 * What about an additional field or flag on
13662 * xmlXPathObject like @sorted ? This way we wouln'd need
13663 * to assume anything, so it would be more robust and
13664 * easier to optimize.
13665 */
13666 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13667 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13668#else
13669 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13670#endif
13671 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013672 xmlXPathObjectPtr val;
13673
13674 val = comp->steps[op->ch2].value4;
13675 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13676 (val->floatval == 1.0)) {
13677 xmlNodePtr first = NULL;
13678
13679 total +=
13680 xmlXPathCompOpEvalFirst(ctxt,
13681 &comp->steps[op->ch1],
13682 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013683 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013684 /*
13685 * The nodeset should be in document order,
13686 * Keep only the first value
13687 */
13688 if ((ctxt->value != NULL) &&
13689 (ctxt->value->type == XPATH_NODESET) &&
13690 (ctxt->value->nodesetval != NULL) &&
13691 (ctxt->value->nodesetval->nodeNr > 1))
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013692 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13693 1, 1);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013694 return (total);
13695 }
13696 }
13697 /*
13698 * Optimization for ()[last()] selection i.e. the last elem
13699 */
13700 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13701 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13702 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13703 int f = comp->steps[op->ch2].ch1;
13704
13705 if ((f != -1) &&
13706 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13707 (comp->steps[f].value5 == NULL) &&
13708 (comp->steps[f].value == 0) &&
13709 (comp->steps[f].value4 != NULL) &&
13710 (xmlStrEqual
13711 (comp->steps[f].value4, BAD_CAST "last"))) {
13712 xmlNodePtr last = NULL;
13713
13714 total +=
13715 xmlXPathCompOpEvalLast(ctxt,
13716 &comp->steps[op->ch1],
13717 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013718 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013719 /*
13720 * The nodeset should be in document order,
13721 * Keep only the last value
13722 */
13723 if ((ctxt->value != NULL) &&
13724 (ctxt->value->type == XPATH_NODESET) &&
13725 (ctxt->value->nodesetval != NULL) &&
13726 (ctxt->value->nodesetval->nodeTab != NULL) &&
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013727 (ctxt->value->nodesetval->nodeNr > 1))
13728 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013729 return (total);
13730 }
13731 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013732 /*
13733 * Process inner predicates first.
13734 * Example "index[parent::book][1]":
13735 * ...
13736 * PREDICATE <-- we are here "[1]"
13737 * PREDICATE <-- process "[parent::book]" first
13738 * SORT
13739 * COLLECT 'parent' 'name' 'node' book
13740 * NODE
13741 * ELEM Object is a number : 1
13742 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013743 if (op->ch1 != -1)
13744 total +=
13745 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013746 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013747 if (op->ch2 == -1)
13748 return (total);
13749 if (ctxt->value == NULL)
13750 return (total);
13751
13752 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013753
13754#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013755 /*
13756 * Hum are we filtering the result of an XPointer expression
13757 */
13758 if (ctxt->value->type == XPATH_LOCATIONSET) {
13759 xmlLocationSetPtr newlocset = NULL;
13760 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013761
Daniel Veillardf06307e2001-07-03 10:35:50 +000013762 /*
13763 * Extract the old locset, and then evaluate the result of the
13764 * expression for all the element in the locset. use it to grow
13765 * up a new locset.
13766 */
13767 CHECK_TYPE0(XPATH_LOCATIONSET);
13768 obj = valuePop(ctxt);
13769 oldlocset = obj->user;
13770 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013771
Daniel Veillardf06307e2001-07-03 10:35:50 +000013772 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13773 ctxt->context->contextSize = 0;
13774 ctxt->context->proximityPosition = 0;
13775 if (op->ch2 != -1)
13776 total +=
13777 xmlXPathCompOpEval(ctxt,
13778 &comp->steps[op->ch2]);
13779 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013780 if (res != NULL) {
13781 xmlXPathReleaseObject(ctxt->context, res);
13782 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013783 valuePush(ctxt, obj);
13784 CHECK_ERROR0;
13785 return (total);
13786 }
13787 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013788
Daniel Veillardf06307e2001-07-03 10:35:50 +000013789 for (i = 0; i < oldlocset->locNr; i++) {
13790 /*
13791 * Run the evaluation with a node list made of a
13792 * single item in the nodelocset.
13793 */
13794 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013795 ctxt->context->contextSize = oldlocset->locNr;
13796 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013797 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13798 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013799 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013800
Daniel Veillardf06307e2001-07-03 10:35:50 +000013801 if (op->ch2 != -1)
13802 total +=
13803 xmlXPathCompOpEval(ctxt,
13804 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013805 if (ctxt->error != XPATH_EXPRESSION_OK) {
13806 xmlXPathFreeObject(obj);
13807 return(0);
13808 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013809
Daniel Veillardf06307e2001-07-03 10:35:50 +000013810 /*
13811 * The result of the evaluation need to be tested to
13812 * decided whether the filter succeeded or not
13813 */
13814 res = valuePop(ctxt);
13815 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13816 xmlXPtrLocationSetAdd(newlocset,
13817 xmlXPathObjectCopy
13818 (oldlocset->locTab[i]));
13819 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013820
Daniel Veillardf06307e2001-07-03 10:35:50 +000013821 /*
13822 * Cleanup
13823 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013824 if (res != NULL) {
13825 xmlXPathReleaseObject(ctxt->context, res);
13826 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013827 if (ctxt->value == tmp) {
13828 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013829 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013830 }
13831
13832 ctxt->context->node = NULL;
13833 }
13834
13835 /*
13836 * The result is used as the new evaluation locset.
13837 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013838 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013839 ctxt->context->node = NULL;
13840 ctxt->context->contextSize = -1;
13841 ctxt->context->proximityPosition = -1;
13842 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13843 ctxt->context->node = oldnode;
13844 return (total);
13845 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013846#endif /* LIBXML_XPTR_ENABLED */
13847
Daniel Veillardf06307e2001-07-03 10:35:50 +000013848 /*
13849 * Extract the old set, and then evaluate the result of the
13850 * expression for all the element in the set. use it to grow
13851 * up a new set.
13852 */
13853 CHECK_TYPE0(XPATH_NODESET);
13854 obj = valuePop(ctxt);
13855 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013856
Daniel Veillardf06307e2001-07-03 10:35:50 +000013857 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013858 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013859 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013860
Daniel Veillardf06307e2001-07-03 10:35:50 +000013861 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13862 ctxt->context->contextSize = 0;
13863 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013864/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013865 if (op->ch2 != -1)
13866 total +=
13867 xmlXPathCompOpEval(ctxt,
13868 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013869 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013870 res = valuePop(ctxt);
13871 if (res != NULL)
13872 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013873*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013874 valuePush(ctxt, obj);
13875 ctxt->context->node = oldnode;
13876 CHECK_ERROR0;
13877 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013878 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013879 /*
13880 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013881 * Also set the xpath document in case things like
13882 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013883 */
13884 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013885 /*
13886 * SPEC XPath 1.0:
13887 * "For each node in the node-set to be filtered, the
13888 * PredicateExpr is evaluated with that node as the
13889 * context node, with the number of nodes in the
13890 * node-set as the context size, and with the proximity
13891 * position of the node in the node-set with respect to
13892 * the axis as the context position;"
13893 * @oldset is the node-set" to be filtered.
13894 *
13895 * SPEC XPath 1.0:
13896 * "only predicates change the context position and
13897 * context size (see [2.4 Predicates])."
13898 * Example:
13899 * node-set context pos
13900 * nA 1
13901 * nB 2
13902 * nC 3
13903 * After applying predicate [position() > 1] :
13904 * node-set context pos
13905 * nB 1
13906 * nC 2
13907 *
13908 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013909 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013910 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013911 for (i = 0; i < oldset->nodeNr; i++) {
13912 /*
13913 * Run the evaluation with a node list made of
13914 * a single item in the nodeset.
13915 */
13916 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013917 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13918 (oldset->nodeTab[i]->doc != NULL))
13919 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013920 if (tmp == NULL) {
13921 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13922 ctxt->context->node);
13923 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013924 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13925 ctxt->context->node) < 0) {
13926 ctxt->error = XPATH_MEMORY_ERROR;
13927 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013928 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013929 valuePush(ctxt, tmp);
13930 ctxt->context->contextSize = oldset->nodeNr;
13931 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013932 /*
13933 * Evaluate the predicate against the context node.
13934 * Can/should we optimize position() predicates
13935 * here (e.g. "[1]")?
13936 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013937 if (op->ch2 != -1)
13938 total +=
13939 xmlXPathCompOpEval(ctxt,
13940 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013941 if (ctxt->error != XPATH_EXPRESSION_OK) {
13942 xmlXPathFreeNodeSet(newset);
13943 xmlXPathFreeObject(obj);
13944 return(0);
13945 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013946
Daniel Veillardf06307e2001-07-03 10:35:50 +000013947 /*
William M. Brack08171912003-12-29 02:52:11 +000013948 * The result of the evaluation needs to be tested to
13949 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013950 */
13951 /*
13952 * OPTIMIZE TODO: Can we use
13953 * xmlXPathNodeSetAdd*Unique()* instead?
13954 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013955 res = valuePop(ctxt);
13956 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013957 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13958 < 0)
13959 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013960 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013961
Daniel Veillardf06307e2001-07-03 10:35:50 +000013962 /*
13963 * Cleanup
13964 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013965 if (res != NULL) {
13966 xmlXPathReleaseObject(ctxt->context, res);
13967 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013968 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013969 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013970 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013971 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013972 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013973 * in order to avoid massive recreation inside this
13974 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013975 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013976 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013977 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013978 ctxt->context->node = NULL;
13979 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013980 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013981 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013982 /*
13983 * The result is used as the new evaluation set.
13984 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013985 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013986 ctxt->context->node = NULL;
13987 ctxt->context->contextSize = -1;
13988 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013989 /* may want to move this past the '}' later */
13990 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013991 valuePush(ctxt,
13992 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013993 }
13994 ctxt->context->node = oldnode;
13995 return (total);
13996 }
13997 case XPATH_OP_SORT:
13998 if (op->ch1 != -1)
13999 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000014000 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014001 if ((ctxt->value != NULL) &&
14002 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000014003 (ctxt->value->nodesetval != NULL) &&
14004 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014005 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014006 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014007 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014008 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014009#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000014010 case XPATH_OP_RANGETO:{
14011 xmlXPathObjectPtr range;
14012 xmlXPathObjectPtr res, obj;
14013 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000014014 xmlLocationSetPtr newlocset = NULL;
14015 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014016 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000014017 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014018
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020014019 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014020 total +=
14021 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020014022 CHECK_ERROR0;
14023 }
14024 if (ctxt->value == NULL) {
14025 XP_ERROR0(XPATH_INVALID_OPERAND);
14026 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014027 if (op->ch2 == -1)
14028 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014029
William M. Brack08171912003-12-29 02:52:11 +000014030 if (ctxt->value->type == XPATH_LOCATIONSET) {
14031 /*
14032 * Extract the old locset, and then evaluate the result of the
14033 * expression for all the element in the locset. use it to grow
14034 * up a new locset.
14035 */
14036 CHECK_TYPE0(XPATH_LOCATIONSET);
14037 obj = valuePop(ctxt);
14038 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014039
William M. Brack08171912003-12-29 02:52:11 +000014040 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000014041 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000014042 ctxt->context->contextSize = 0;
14043 ctxt->context->proximityPosition = 0;
14044 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14045 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014046 if (res != NULL) {
14047 xmlXPathReleaseObject(ctxt->context, res);
14048 }
William M. Brack08171912003-12-29 02:52:11 +000014049 valuePush(ctxt, obj);
14050 CHECK_ERROR0;
14051 return (total);
14052 }
14053 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014054
William M. Brack08171912003-12-29 02:52:11 +000014055 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014056 /*
William M. Brack08171912003-12-29 02:52:11 +000014057 * Run the evaluation with a node list made of a
14058 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000014059 */
William M. Brackf7eb7942003-12-31 07:59:17 +000014060 ctxt->context->node = oldlocset->locTab[i]->user;
14061 ctxt->context->contextSize = oldlocset->locNr;
14062 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014063 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14064 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014065 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014066
Daniel Veillardf06307e2001-07-03 10:35:50 +000014067 if (op->ch2 != -1)
14068 total +=
14069 xmlXPathCompOpEval(ctxt,
14070 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014071 if (ctxt->error != XPATH_EXPRESSION_OK) {
14072 xmlXPathFreeObject(obj);
14073 return(0);
14074 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014075
Daniel Veillardf06307e2001-07-03 10:35:50 +000014076 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000014077 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014078 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000014079 (xmlLocationSetPtr)res->user;
14080 for (j=0; j<rloc->locNr; j++) {
14081 range = xmlXPtrNewRange(
14082 oldlocset->locTab[i]->user,
14083 oldlocset->locTab[i]->index,
14084 rloc->locTab[j]->user2,
14085 rloc->locTab[j]->index2);
14086 if (range != NULL) {
14087 xmlXPtrLocationSetAdd(newlocset, range);
14088 }
14089 }
14090 } else {
14091 range = xmlXPtrNewRangeNodeObject(
14092 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14093 if (range != NULL) {
14094 xmlXPtrLocationSetAdd(newlocset,range);
14095 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014096 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014097
Daniel Veillardf06307e2001-07-03 10:35:50 +000014098 /*
14099 * Cleanup
14100 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014101 if (res != NULL) {
14102 xmlXPathReleaseObject(ctxt->context, res);
14103 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014104 if (ctxt->value == tmp) {
14105 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014106 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014107 }
14108
14109 ctxt->context->node = NULL;
14110 }
William M. Brack72ee48d2003-12-30 08:30:19 +000014111 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000014112 CHECK_TYPE0(XPATH_NODESET);
14113 obj = valuePop(ctxt);
14114 oldset = obj->nodesetval;
14115 ctxt->context->node = NULL;
14116
14117 newlocset = xmlXPtrLocationSetCreate(NULL);
14118
14119 if (oldset != NULL) {
14120 for (i = 0; i < oldset->nodeNr; i++) {
14121 /*
14122 * Run the evaluation with a node list made of a single item
14123 * in the nodeset.
14124 */
14125 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014126 /*
14127 * OPTIMIZE TODO: Avoid recreation for every iteration.
14128 */
14129 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14130 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000014131 valuePush(ctxt, tmp);
14132
14133 if (op->ch2 != -1)
14134 total +=
14135 xmlXPathCompOpEval(ctxt,
14136 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014137 if (ctxt->error != XPATH_EXPRESSION_OK) {
14138 xmlXPathFreeObject(obj);
14139 return(0);
14140 }
William M. Brack08171912003-12-29 02:52:11 +000014141
William M. Brack08171912003-12-29 02:52:11 +000014142 res = valuePop(ctxt);
14143 range =
14144 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14145 res);
14146 if (range != NULL) {
14147 xmlXPtrLocationSetAdd(newlocset, range);
14148 }
14149
14150 /*
14151 * Cleanup
14152 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014153 if (res != NULL) {
14154 xmlXPathReleaseObject(ctxt->context, res);
14155 }
William M. Brack08171912003-12-29 02:52:11 +000014156 if (ctxt->value == tmp) {
14157 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014158 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000014159 }
14160
14161 ctxt->context->node = NULL;
14162 }
14163 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014164 }
14165
14166 /*
14167 * The result is used as the new evaluation set.
14168 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014169 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014170 ctxt->context->node = NULL;
14171 ctxt->context->contextSize = -1;
14172 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000014173 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014174 return (total);
14175 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014176#endif /* LIBXML_XPTR_ENABLED */
14177 }
14178 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000014179 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080014180 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014181 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014182}
14183
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014184/**
14185 * xmlXPathCompOpEvalToBoolean:
14186 * @ctxt: the XPath parser context
14187 *
14188 * Evaluates if the expression evaluates to true.
14189 *
14190 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14191 */
14192static int
14193xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014194 xmlXPathStepOpPtr op,
14195 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014196{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014197 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014198
14199start:
14200 /* comp = ctxt->comp; */
14201 switch (op->op) {
14202 case XPATH_OP_END:
14203 return (0);
14204 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014205 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014206 if (isPredicate)
14207 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14208 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014209 case XPATH_OP_SORT:
14210 /*
14211 * We don't need sorting for boolean results. Skip this one.
14212 */
14213 if (op->ch1 != -1) {
14214 op = &ctxt->comp->steps[op->ch1];
14215 goto start;
14216 }
14217 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014218 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014219 if (op->ch1 == -1)
14220 return(0);
14221
14222 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14223 if (ctxt->error != XPATH_EXPRESSION_OK)
14224 return(-1);
14225
14226 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14227 if (ctxt->error != XPATH_EXPRESSION_OK)
14228 return(-1);
14229
14230 resObj = valuePop(ctxt);
14231 if (resObj == NULL)
14232 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014233 break;
14234 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014235 /*
14236 * Fallback to call xmlXPathCompOpEval().
14237 */
14238 xmlXPathCompOpEval(ctxt, op);
14239 if (ctxt->error != XPATH_EXPRESSION_OK)
14240 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014241
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014242 resObj = valuePop(ctxt);
14243 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014244 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014245 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014246 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014247
14248 if (resObj) {
14249 int res;
14250
14251 if (resObj->type == XPATH_BOOLEAN) {
14252 res = resObj->boolval;
14253 } else if (isPredicate) {
14254 /*
14255 * For predicates a result of type "number" is handled
14256 * differently:
14257 * SPEC XPath 1.0:
14258 * "If the result is a number, the result will be converted
14259 * to true if the number is equal to the context position
14260 * and will be converted to false otherwise;"
14261 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014262 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014263 } else {
14264 res = xmlXPathCastToBoolean(resObj);
14265 }
14266 xmlXPathReleaseObject(ctxt->context, resObj);
14267 return(res);
14268 }
14269
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014270 return(0);
14271}
14272
Daniel Veillard56de87e2005-02-16 00:22:29 +000014273#ifdef XPATH_STREAMING
14274/**
14275 * xmlXPathRunStreamEval:
14276 * @ctxt: the XPath parser context with the compiled expression
14277 *
14278 * Evaluate the Precompiled Streamable XPath expression in the given context.
14279 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014280static int
14281xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14282 xmlXPathObjectPtr *resultSeq, int toBool)
14283{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014284 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014285 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014286 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014287 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014288 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014289 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014290
14291 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014292
14293 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014294 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014295 max_depth = xmlPatternMaxDepth(comp);
14296 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014297 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014298 if (max_depth == -2)
14299 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014300 min_depth = xmlPatternMinDepth(comp);
14301 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014302 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014303 from_root = xmlPatternFromRoot(comp);
14304 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014305 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014306#if 0
14307 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14308#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014309
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014310 if (! toBool) {
14311 if (resultSeq == NULL)
14312 return(-1);
14313 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14314 if (*resultSeq == NULL)
14315 return(-1);
14316 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014317
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014318 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014319 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014320 */
14321 if (min_depth == 0) {
14322 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014323 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014324 if (toBool)
14325 return(1);
14326 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014327 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014328 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014329 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014330 if (toBool)
14331 return(1);
14332 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014333 }
14334 }
14335 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014336 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014337 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014338
Daniel Veillard56de87e2005-02-16 00:22:29 +000014339 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014340 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014341 } else if (ctxt->node != NULL) {
14342 switch (ctxt->node->type) {
14343 case XML_ELEMENT_NODE:
14344 case XML_DOCUMENT_NODE:
14345 case XML_DOCUMENT_FRAG_NODE:
14346 case XML_HTML_DOCUMENT_NODE:
14347#ifdef LIBXML_DOCB_ENABLED
14348 case XML_DOCB_DOCUMENT_NODE:
14349#endif
14350 cur = ctxt->node;
14351 break;
14352 case XML_ATTRIBUTE_NODE:
14353 case XML_TEXT_NODE:
14354 case XML_CDATA_SECTION_NODE:
14355 case XML_ENTITY_REF_NODE:
14356 case XML_ENTITY_NODE:
14357 case XML_PI_NODE:
14358 case XML_COMMENT_NODE:
14359 case XML_NOTATION_NODE:
14360 case XML_DTD_NODE:
14361 case XML_DOCUMENT_TYPE_NODE:
14362 case XML_ELEMENT_DECL:
14363 case XML_ATTRIBUTE_DECL:
14364 case XML_ENTITY_DECL:
14365 case XML_NAMESPACE_DECL:
14366 case XML_XINCLUDE_START:
14367 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014368 break;
14369 }
14370 limit = cur;
14371 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014372 if (cur == NULL) {
14373 return(0);
14374 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014375
14376 patstream = xmlPatternGetStreamCtxt(comp);
14377 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014378 /*
14379 * QUESTION TODO: Is this an error?
14380 */
14381 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014382 }
14383
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014384 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014385
Daniel Veillard56de87e2005-02-16 00:22:29 +000014386 if (from_root) {
14387 ret = xmlStreamPush(patstream, NULL, NULL);
14388 if (ret < 0) {
14389 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014390 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014391 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014392 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014393 }
14394 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014395 depth = 0;
14396 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014397next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014398 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014399 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014400
14401 switch (cur->type) {
14402 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014403 case XML_TEXT_NODE:
14404 case XML_CDATA_SECTION_NODE:
14405 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014406 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014407 if (cur->type == XML_ELEMENT_NODE) {
14408 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014409 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014410 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014411 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14412 else
14413 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014414
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014415 if (ret < 0) {
14416 /* NOP. */
14417 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014418 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014419 goto return_1;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014420 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14421 < 0) {
14422 ctxt->lastError.domain = XML_FROM_XPATH;
14423 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14424 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014425 }
14426 if ((cur->children == NULL) || (depth >= max_depth)) {
14427 ret = xmlStreamPop(patstream);
14428 while (cur->next != NULL) {
14429 cur = cur->next;
14430 if ((cur->type != XML_ENTITY_DECL) &&
14431 (cur->type != XML_DTD_NODE))
14432 goto next_node;
14433 }
14434 }
14435 default:
14436 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014437 }
14438
Daniel Veillard56de87e2005-02-16 00:22:29 +000014439scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080014440 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014441 if ((cur->children != NULL) && (depth < max_depth)) {
14442 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014443 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014444 */
14445 if (cur->children->type != XML_ENTITY_DECL) {
14446 cur = cur->children;
14447 depth++;
14448 /*
14449 * Skip DTDs
14450 */
14451 if (cur->type != XML_DTD_NODE)
14452 continue;
14453 }
14454 }
14455
14456 if (cur == limit)
14457 break;
14458
14459 while (cur->next != NULL) {
14460 cur = cur->next;
14461 if ((cur->type != XML_ENTITY_DECL) &&
14462 (cur->type != XML_DTD_NODE))
14463 goto next_node;
14464 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014465
Daniel Veillard56de87e2005-02-16 00:22:29 +000014466 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014467 cur = cur->parent;
14468 depth--;
14469 if ((cur == NULL) || (cur == limit))
14470 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014471 if (cur->type == XML_ELEMENT_NODE) {
14472 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014473 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014474 ((cur->type == XML_TEXT_NODE) ||
14475 (cur->type == XML_CDATA_SECTION_NODE) ||
14476 (cur->type == XML_COMMENT_NODE) ||
14477 (cur->type == XML_PI_NODE)))
14478 {
14479 ret = xmlStreamPop(patstream);
14480 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014481 if (cur->next != NULL) {
14482 cur = cur->next;
14483 break;
14484 }
14485 } while (cur != NULL);
14486
14487 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014488
Daniel Veillard56de87e2005-02-16 00:22:29 +000014489done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014490
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014491#if 0
14492 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014493 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014494#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014495
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014496 if (patstream)
14497 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014498 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014499
14500return_1:
14501 if (patstream)
14502 xmlFreeStreamCtxt(patstream);
14503 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014504}
14505#endif /* XPATH_STREAMING */
14506
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014507/**
14508 * xmlXPathRunEval:
14509 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014510 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014511 *
14512 * Evaluate the Precompiled XPath expression in the given context.
14513 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014514static int
14515xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14516{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014517 xmlXPathCompExprPtr comp;
14518
14519 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014520 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014521
14522 if (ctxt->valueTab == NULL) {
14523 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014524 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014525 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14526 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014527 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014528 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014529 }
14530 ctxt->valueNr = 0;
14531 ctxt->valueMax = 10;
14532 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014533 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014534 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014535#ifdef XPATH_STREAMING
14536 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014537 int res;
14538
14539 if (toBool) {
14540 /*
14541 * Evaluation to boolean result.
14542 */
14543 res = xmlXPathRunStreamEval(ctxt->context,
14544 ctxt->comp->stream, NULL, 1);
14545 if (res != -1)
14546 return(res);
14547 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014548 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014549
14550 /*
14551 * Evaluation to a sequence.
14552 */
14553 res = xmlXPathRunStreamEval(ctxt->context,
14554 ctxt->comp->stream, &resObj, 0);
14555
14556 if ((res != -1) && (resObj != NULL)) {
14557 valuePush(ctxt, resObj);
14558 return(0);
14559 }
14560 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014561 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014562 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014563 /*
14564 * QUESTION TODO: This falls back to normal XPath evaluation
14565 * if res == -1. Is this intended?
14566 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014567 }
14568#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014569 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014570 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014571 xmlGenericError(xmlGenericErrorContext,
14572 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014573 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014574 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014575 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014576 return(xmlXPathCompOpEvalToBoolean(ctxt,
14577 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014578 else
14579 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14580
14581 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014582}
14583
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014584/************************************************************************
14585 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014586 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014587 * *
14588 ************************************************************************/
14589
14590/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014591 * xmlXPathEvalPredicate:
14592 * @ctxt: the XPath context
14593 * @res: the Predicate Expression evaluation result
14594 *
14595 * Evaluate a predicate result for the current node.
14596 * A PredicateExpr is evaluated by evaluating the Expr and converting
14597 * the result to a boolean. If the result is a number, the result will
14598 * be converted to true if the number is equal to the position of the
14599 * context node in the context node list (as returned by the position
14600 * function) and will be converted to false otherwise; if the result
14601 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014602 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014603 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014604 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014605 */
14606int
14607xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014608 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014609 switch (res->type) {
14610 case XPATH_BOOLEAN:
14611 return(res->boolval);
14612 case XPATH_NUMBER:
14613 return(res->floatval == ctxt->proximityPosition);
14614 case XPATH_NODESET:
14615 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014616 if (res->nodesetval == NULL)
14617 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014618 return(res->nodesetval->nodeNr != 0);
14619 case XPATH_STRING:
14620 return((res->stringval != NULL) &&
14621 (xmlStrlen(res->stringval) != 0));
14622 default:
14623 STRANGE
14624 }
14625 return(0);
14626}
14627
14628/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014629 * xmlXPathEvaluatePredicateResult:
14630 * @ctxt: the XPath Parser context
14631 * @res: the Predicate Expression evaluation result
14632 *
14633 * Evaluate a predicate result for the current node.
14634 * A PredicateExpr is evaluated by evaluating the Expr and converting
14635 * the result to a boolean. If the result is a number, the result will
14636 * be converted to true if the number is equal to the position of the
14637 * context node in the context node list (as returned by the position
14638 * function) and will be converted to false otherwise; if the result
14639 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014640 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014641 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014642 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014643 */
14644int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014645xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014646 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014647 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014648 switch (res->type) {
14649 case XPATH_BOOLEAN:
14650 return(res->boolval);
14651 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014652#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014653 return((res->floatval == ctxt->context->proximityPosition) &&
14654 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014655#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014656 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014657#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014658 case XPATH_NODESET:
14659 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014660 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014661 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014662 return(res->nodesetval->nodeNr != 0);
14663 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014664 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014665#ifdef LIBXML_XPTR_ENABLED
14666 case XPATH_LOCATIONSET:{
14667 xmlLocationSetPtr ptr = res->user;
14668 if (ptr == NULL)
14669 return(0);
14670 return (ptr->locNr != 0);
14671 }
14672#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014673 default:
14674 STRANGE
14675 }
14676 return(0);
14677}
14678
Daniel Veillard56de87e2005-02-16 00:22:29 +000014679#ifdef XPATH_STREAMING
14680/**
14681 * xmlXPathTryStreamCompile:
14682 * @ctxt: an XPath context
14683 * @str: the XPath expression
14684 *
14685 * Try to compile the XPath expression as a streamable subset.
14686 *
14687 * Returns the compiled expression or NULL if failed to compile.
14688 */
14689static xmlXPathCompExprPtr
14690xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14691 /*
14692 * Optimization: use streaming patterns when the XPath expression can
14693 * be compiled to a stream lookup
14694 */
14695 xmlPatternPtr stream;
14696 xmlXPathCompExprPtr comp;
14697 xmlDictPtr dict = NULL;
14698 const xmlChar **namespaces = NULL;
14699 xmlNsPtr ns;
14700 int i, j;
14701
14702 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14703 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014704 const xmlChar *tmp;
14705
14706 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014707 * We don't try to handle expressions using the verbose axis
14708 * specifiers ("::"), just the simplied form at this point.
14709 * Additionally, if there is no list of namespaces available and
14710 * there's a ":" in the expression, indicating a prefixed QName,
14711 * then we won't try to compile either. xmlPatterncompile() needs
14712 * to have a list of namespaces at compilation time in order to
14713 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014714 */
14715 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014716 if ((tmp != NULL) &&
14717 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014718 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014719
Daniel Veillard56de87e2005-02-16 00:22:29 +000014720 if (ctxt != NULL) {
14721 dict = ctxt->dict;
14722 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014723 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014724 if (namespaces == NULL) {
14725 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14726 return(NULL);
14727 }
14728 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14729 ns = ctxt->namespaces[j];
14730 namespaces[i++] = ns->href;
14731 namespaces[i++] = ns->prefix;
14732 }
14733 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014734 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014735 }
14736 }
14737
William M. Brackea152c02005-06-09 18:12:28 +000014738 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14739 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014740 if (namespaces != NULL) {
14741 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014742 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014743 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14744 comp = xmlXPathNewCompExpr();
14745 if (comp == NULL) {
14746 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14747 return(NULL);
14748 }
14749 comp->stream = stream;
14750 comp->dict = dict;
14751 if (comp->dict)
14752 xmlDictReference(comp->dict);
14753 return(comp);
14754 }
14755 xmlFreePattern(stream);
14756 }
14757 return(NULL);
14758}
14759#endif /* XPATH_STREAMING */
14760
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014761static void
Nick Wellnhofer62270532012-08-19 19:42:38 +020014762xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014763{
14764 /*
14765 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14766 * internal representation.
14767 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014768
Nick Wellnhoferb4bcba22013-08-05 00:15:11 +020014769 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14770 (op->ch1 != -1) &&
14771 (op->ch2 == -1 /* no predicate */))
Nick Wellnhofer62270532012-08-19 19:42:38 +020014772 {
14773 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14774
14775 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14776 ((xmlXPathAxisVal) prevop->value ==
14777 AXIS_DESCENDANT_OR_SELF) &&
14778 (prevop->ch2 == -1) &&
14779 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14780 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14781 {
14782 /*
14783 * This is a "descendant-or-self::node()" without predicates.
14784 * Try to eliminate it.
14785 */
14786
14787 switch ((xmlXPathAxisVal) op->value) {
14788 case AXIS_CHILD:
14789 case AXIS_DESCENDANT:
14790 /*
14791 * Convert "descendant-or-self::node()/child::" or
14792 * "descendant-or-self::node()/descendant::" to
14793 * "descendant::"
14794 */
14795 op->ch1 = prevop->ch1;
14796 op->value = AXIS_DESCENDANT;
14797 break;
14798 case AXIS_SELF:
14799 case AXIS_DESCENDANT_OR_SELF:
14800 /*
14801 * Convert "descendant-or-self::node()/self::" or
14802 * "descendant-or-self::node()/descendant-or-self::" to
14803 * to "descendant-or-self::"
14804 */
14805 op->ch1 = prevop->ch1;
14806 op->value = AXIS_DESCENDANT_OR_SELF;
14807 break;
14808 default:
14809 break;
14810 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014811 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014812 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014813
Nick Wellnhofer839689a2016-04-27 18:00:12 +020014814 /* OP_VALUE has invalid ch1. */
14815 if (op->op == XPATH_OP_VALUE)
14816 return;
14817
Nick Wellnhofer62270532012-08-19 19:42:38 +020014818 /* Recurse */
14819 if (op->ch1 != -1)
14820 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014821 if (op->ch2 != -1)
Nick Wellnhofer62270532012-08-19 19:42:38 +020014822 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014823}
14824
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014825/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014826 * xmlXPathCtxtCompile:
14827 * @ctxt: an XPath context
14828 * @str: the XPath expression
14829 *
14830 * Compile an XPath expression
14831 *
14832 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14833 * the caller has to free the object.
14834 */
14835xmlXPathCompExprPtr
14836xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14837 xmlXPathParserContextPtr pctxt;
14838 xmlXPathCompExprPtr comp;
14839
Daniel Veillard56de87e2005-02-16 00:22:29 +000014840#ifdef XPATH_STREAMING
14841 comp = xmlXPathTryStreamCompile(ctxt, str);
14842 if (comp != NULL)
14843 return(comp);
14844#endif
14845
Daniel Veillard4773df22004-01-23 13:15:13 +000014846 xmlXPathInit();
14847
14848 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014849 if (pctxt == NULL)
14850 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014851 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014852
14853 if( pctxt->error != XPATH_EXPRESSION_OK )
14854 {
14855 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014856 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014857 }
14858
14859 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014860 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014861 * aleksey: in some cases this line prints *second* error message
14862 * (see bug #78858) and probably this should be fixed.
14863 * However, we are not sure that all error messages are printed
14864 * out in other places. It's not critical so we leave it as-is for now
14865 */
14866 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14867 comp = NULL;
14868 } else {
14869 comp = pctxt->comp;
14870 pctxt->comp = NULL;
14871 }
14872 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014873
Daniel Veillard4773df22004-01-23 13:15:13 +000014874 if (comp != NULL) {
14875 comp->expr = xmlStrdup(str);
14876#ifdef DEBUG_EVAL_COUNTS
14877 comp->string = xmlStrdup(str);
14878 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014879#endif
Nick Wellnhofer62270532012-08-19 19:42:38 +020014880 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14881 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014882 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014883 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014884 return(comp);
14885}
14886
14887/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014888 * xmlXPathCompile:
14889 * @str: the XPath expression
14890 *
14891 * Compile an XPath expression
14892 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014893 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014894 * the caller has to free the object.
14895 */
14896xmlXPathCompExprPtr
14897xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014898 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014899}
14900
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014901/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014902 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014903 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014904 * @ctxt: the XPath context
14905 * @resObj: the resulting XPath object or NULL
14906 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014907 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014908 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014909 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014910 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014911 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014912 * the caller has to free the object.
14913 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014914static int
14915xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14916 xmlXPathContextPtr ctxt,
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014917 xmlXPathObjectPtr *resObjPtr,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014918 int toBool)
14919{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014920 xmlXPathParserContextPtr pctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014921 xmlXPathObjectPtr resObj;
Daniel Veillard81463942001-10-16 12:34:39 +000014922#ifndef LIBXML_THREAD_ENABLED
14923 static int reentance = 0;
14924#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014925 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014926
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014927 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014928
14929 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014930 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014931 xmlXPathInit();
14932
Daniel Veillard81463942001-10-16 12:34:39 +000014933#ifndef LIBXML_THREAD_ENABLED
14934 reentance++;
14935 if (reentance > 1)
14936 xmlXPathDisableOptimizer = 1;
14937#endif
14938
Daniel Veillardf06307e2001-07-03 10:35:50 +000014939#ifdef DEBUG_EVAL_COUNTS
14940 comp->nb++;
14941 if ((comp->string != NULL) && (comp->nb > 100)) {
14942 fprintf(stderr, "100 x %s\n", comp->string);
14943 comp->nb = 0;
14944 }
14945#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014946 pctxt = xmlXPathCompParserContext(comp, ctxt);
14947 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014948
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014949 if (pctxt->error != XPATH_EXPRESSION_OK) {
14950 resObj = NULL;
14951 } else {
14952 resObj = valuePop(pctxt);
14953 if (resObj == NULL) {
Nick Wellnhofera07a4e92017-05-27 17:04:12 +020014954 if (!toBool)
14955 xmlGenericError(xmlGenericErrorContext,
14956 "xmlXPathCompiledEval: No result on the stack.\n");
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014957 } else if (pctxt->valueNr > 0) {
14958 xmlGenericError(xmlGenericErrorContext,
14959 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14960 pctxt->valueNr);
14961 }
Owen Taylor3473f882001-02-23 17:55:21 +000014962 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014963
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014964 if (resObjPtr)
14965 *resObjPtr = resObj;
14966 else
14967 xmlXPathReleaseObject(ctxt, resObj);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014968
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014969 pctxt->comp = NULL;
14970 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014971#ifndef LIBXML_THREAD_ENABLED
14972 reentance--;
14973#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014974
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014975 return(res);
14976}
14977
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014978/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014979 * xmlXPathCompiledEval:
14980 * @comp: the compiled XPath expression
14981 * @ctx: the XPath context
14982 *
14983 * Evaluate the Precompiled XPath expression in the given context.
14984 *
14985 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14986 * the caller has to free the object.
14987 */
14988xmlXPathObjectPtr
14989xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14990{
14991 xmlXPathObjectPtr res = NULL;
14992
14993 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14994 return(res);
14995}
14996
14997/**
14998 * xmlXPathCompiledEvalToBoolean:
14999 * @comp: the compiled XPath expression
15000 * @ctxt: the XPath context
15001 *
15002 * Applies the XPath boolean() function on the result of the given
15003 * compiled expression.
15004 *
15005 * Returns 1 if the expression evaluated to true, 0 if to false and
15006 * -1 in API and internal errors.
15007 */
15008int
15009xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
15010 xmlXPathContextPtr ctxt)
15011{
15012 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
15013}
15014
15015/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000015016 * xmlXPathEvalExpr:
15017 * @ctxt: the XPath Parser context
15018 *
15019 * Parse and evaluate an XPath expression in the given context,
15020 * then push the result on the context stack
15021 */
15022void
15023xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000015024#ifdef XPATH_STREAMING
15025 xmlXPathCompExprPtr comp;
15026#endif
15027
Daniel Veillarda82b1822004-11-08 16:24:57 +000015028 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015029
Daniel Veillard56de87e2005-02-16 00:22:29 +000015030#ifdef XPATH_STREAMING
15031 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15032 if (comp != NULL) {
15033 if (ctxt->comp != NULL)
15034 xmlXPathFreeCompExpr(ctxt->comp);
15035 ctxt->comp = comp;
Daniel Veillard56de87e2005-02-16 00:22:29 +000015036 } else
15037#endif
15038 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000015039 xmlXPathCompileExpr(ctxt, 1);
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020015040 CHECK_ERROR;
15041
15042 /* Check for trailing characters. */
15043 if (*ctxt->cur != 0)
15044 XP_ERROR(XPATH_EXPR_ERROR);
15045
15046 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
Nick Wellnhofer62270532012-08-19 19:42:38 +020015047 xmlXPathOptimizeExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000015048 &ctxt->comp->steps[ctxt->comp->last]);
Daniel Veillard56de87e2005-02-16 00:22:29 +000015049 }
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020015050
Daniel Veillard45490ae2008-07-29 09:13:19 +000015051 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000015052}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015053
15054/**
15055 * xmlXPathEval:
15056 * @str: the XPath expression
15057 * @ctx: the XPath context
15058 *
15059 * Evaluate the XPath Location Path in the given context.
15060 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000015061 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015062 * the caller has to free the object.
15063 */
15064xmlXPathObjectPtr
15065xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15066 xmlXPathParserContextPtr ctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020015067 xmlXPathObjectPtr res;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015068
William M. Brackf13f77f2004-11-12 16:03:48 +000015069 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015070
William M. Brackf13f77f2004-11-12 16:03:48 +000015071 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015072
15073 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000015074 if (ctxt == NULL)
15075 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015076 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015077
Nick Wellnhoferc8519702017-05-27 15:26:11 +020015078 if (ctxt->error != XPATH_EXPRESSION_OK) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015079 res = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015080 } else {
15081 res = valuePop(ctxt);
Nick Wellnhoferc8519702017-05-27 15:26:11 +020015082 if (res == NULL) {
15083 xmlGenericError(xmlGenericErrorContext,
15084 "xmlXPathCompiledEval: No result on the stack.\n");
15085 } else if (ctxt->valueNr > 0) {
15086 xmlGenericError(xmlGenericErrorContext,
15087 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
15088 ctxt->valueNr);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015089 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015090 }
15091
Owen Taylor3473f882001-02-23 17:55:21 +000015092 xmlXPathFreeParserContext(ctxt);
15093 return(res);
15094}
15095
15096/**
Alex Bligh28876af2013-03-23 17:23:27 +000015097 * xmlXPathSetContextNode:
15098 * @node: the node to to use as the context node
15099 * @ctx: the XPath context
15100 *
15101 * Sets 'node' as the context node. The node must be in the same
15102 * document as that associated with the context.
15103 *
15104 * Returns -1 in case of error or 0 if successful
15105 */
15106int
15107xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15108 if ((node == NULL) || (ctx == NULL))
15109 return(-1);
15110
15111 if (node->doc == ctx->doc) {
15112 ctx->node = node;
15113 return(0);
15114 }
15115 return(-1);
15116}
15117
15118/**
15119 * xmlXPathNodeEval:
15120 * @node: the node to to use as the context node
15121 * @str: the XPath expression
15122 * @ctx: the XPath context
15123 *
15124 * Evaluate the XPath Location Path in the given context. The node 'node'
15125 * is set as the context node. The context node is not restored.
15126 *
15127 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15128 * the caller has to free the object.
15129 */
15130xmlXPathObjectPtr
15131xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15132 if (str == NULL)
15133 return(NULL);
15134 if (xmlXPathSetContextNode(node, ctx) < 0)
15135 return(NULL);
15136 return(xmlXPathEval(str, ctx));
15137}
15138
15139/**
Owen Taylor3473f882001-02-23 17:55:21 +000015140 * xmlXPathEvalExpression:
15141 * @str: the XPath expression
15142 * @ctxt: the XPath context
15143 *
Nick Wellnhofer640a3682017-05-27 14:59:49 +020015144 * Alias for xmlXPathEval.
Owen Taylor3473f882001-02-23 17:55:21 +000015145 */
15146xmlXPathObjectPtr
15147xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Nick Wellnhofer640a3682017-05-27 14:59:49 +020015148 return(xmlXPathEval(str, ctxt));
Owen Taylor3473f882001-02-23 17:55:21 +000015149}
15150
Daniel Veillard42766c02002-08-22 20:52:17 +000015151/************************************************************************
15152 * *
15153 * Extra functions not pertaining to the XPath spec *
15154 * *
15155 ************************************************************************/
15156/**
15157 * xmlXPathEscapeUriFunction:
15158 * @ctxt: the XPath Parser context
15159 * @nargs: the number of arguments
15160 *
15161 * Implement the escape-uri() XPath function
15162 * string escape-uri(string $str, bool $escape-reserved)
15163 *
15164 * This function applies the URI escaping rules defined in section 2 of [RFC
15165 * 2396] to the string supplied as $uri-part, which typically represents all
15166 * or part of a URI. The effect of the function is to replace any special
15167 * character in the string by an escape sequence of the form %xx%yy...,
15168 * where xxyy... is the hexadecimal representation of the octets used to
15169 * represent the character in UTF-8.
15170 *
15171 * The set of characters that are escaped depends on the setting of the
15172 * boolean argument $escape-reserved.
15173 *
15174 * If $escape-reserved is true, all characters are escaped other than lower
15175 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15176 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15177 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15178 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15179 * A-F).
15180 *
15181 * If $escape-reserved is false, the behavior differs in that characters
15182 * referred to in [RFC 2396] as reserved characters are not escaped. These
15183 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015184 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015185 * [RFC 2396] does not define whether escaped URIs should use lower case or
15186 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15187 * compared using string comparison functions, this function must always use
15188 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015189 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015190 * Generally, $escape-reserved should be set to true when escaping a string
15191 * that is to form a single part of a URI, and to false when escaping an
15192 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015193 *
15194 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015195 * utf-8 and then converted according to RFC 2396.
15196 *
15197 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015198 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015199 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15200 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15201 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15202 *
15203 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015204static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015205xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15206 xmlXPathObjectPtr str;
15207 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080015208 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000015209 xmlChar *cptr;
15210 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015211
Daniel Veillard42766c02002-08-22 20:52:17 +000015212 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015213
Daniel Veillard42766c02002-08-22 20:52:17 +000015214 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015215
Daniel Veillard42766c02002-08-22 20:52:17 +000015216 CAST_TO_STRING;
15217 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015218
Daniel Veillardade10f22012-07-12 09:43:27 +080015219 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015220
Daniel Veillard42766c02002-08-22 20:52:17 +000015221 escape[0] = '%';
15222 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015223
Daniel Veillard42766c02002-08-22 20:52:17 +000015224 if (target) {
15225 for (cptr = str->stringval; *cptr; cptr++) {
15226 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15227 (*cptr >= 'a' && *cptr <= 'z') ||
15228 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015229 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015230 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15231 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015232 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015233 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15234 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15235 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15236 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15237 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15238 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15239 (!escape_reserved &&
15240 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15241 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15242 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15243 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080015244 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000015245 } else {
15246 if ((*cptr >> 4) < 10)
15247 escape[1] = '0' + (*cptr >> 4);
15248 else
15249 escape[1] = 'A' - 10 + (*cptr >> 4);
15250 if ((*cptr & 0xF) < 10)
15251 escape[2] = '0' + (*cptr & 0xF);
15252 else
15253 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015254
Daniel Veillardade10f22012-07-12 09:43:27 +080015255 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000015256 }
15257 }
15258 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015259 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080015260 xmlBufContent(target)));
15261 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015262 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015263}
15264
Owen Taylor3473f882001-02-23 17:55:21 +000015265/**
15266 * xmlXPathRegisterAllFunctions:
15267 * @ctxt: the XPath context
15268 *
15269 * Registers all default XPath functions in this context
15270 */
15271void
15272xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15273{
15274 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15275 xmlXPathBooleanFunction);
15276 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15277 xmlXPathCeilingFunction);
15278 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15279 xmlXPathCountFunction);
15280 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15281 xmlXPathConcatFunction);
15282 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15283 xmlXPathContainsFunction);
15284 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15285 xmlXPathIdFunction);
15286 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15287 xmlXPathFalseFunction);
15288 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15289 xmlXPathFloorFunction);
15290 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15291 xmlXPathLastFunction);
15292 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15293 xmlXPathLangFunction);
15294 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15295 xmlXPathLocalNameFunction);
15296 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15297 xmlXPathNotFunction);
15298 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15299 xmlXPathNameFunction);
15300 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15301 xmlXPathNamespaceURIFunction);
15302 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15303 xmlXPathNormalizeFunction);
15304 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15305 xmlXPathNumberFunction);
15306 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15307 xmlXPathPositionFunction);
15308 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15309 xmlXPathRoundFunction);
15310 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15311 xmlXPathStringFunction);
15312 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15313 xmlXPathStringLengthFunction);
15314 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15315 xmlXPathStartsWithFunction);
15316 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15317 xmlXPathSubstringFunction);
15318 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15319 xmlXPathSubstringBeforeFunction);
15320 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15321 xmlXPathSubstringAfterFunction);
15322 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15323 xmlXPathSumFunction);
15324 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15325 xmlXPathTrueFunction);
15326 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15327 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015328
15329 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15330 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15331 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015332}
15333
15334#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015335#define bottom_xpath
15336#include "elfgcchack.h"