blob: 352747313f0b62b2acad6650ac384988802fce70 [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
Stéphane Michaut454e3972017-08-28 14:30:43 +020017/* To avoid EBCDIC trouble when parsing on zOS */
18#if defined(__MVS__)
19#pragma convert("ISO8859-1")
20#endif
21
Daniel Veillard34ce8be2002-03-18 19:37:11 +000022#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000023#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000024
Nick Wellnhofera58331a2017-05-29 21:02:21 +020025#include <limits.h>
Owen Taylor3473f882001-02-23 17:55:21 +000026#include <string.h>
Nick Wellnhoferd422b952017-10-09 13:37:42 +020027#include <stddef.h>
Owen Taylor3473f882001-02-23 17:55:21 +000028
29#ifdef HAVE_SYS_TYPES_H
30#include <sys/types.h>
31#endif
32#ifdef HAVE_MATH_H
33#include <math.h>
34#endif
35#ifdef HAVE_FLOAT_H
36#include <float.h>
37#endif
Owen Taylor3473f882001-02-23 17:55:21 +000038#ifdef HAVE_CTYPE_H
39#include <ctype.h>
40#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000041#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000042#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000043#endif
Owen Taylor3473f882001-02-23 17:55:21 +000044
45#include <libxml/xmlmemory.h>
46#include <libxml/tree.h>
47#include <libxml/valid.h>
48#include <libxml/xpath.h>
49#include <libxml/xpathInternals.h>
50#include <libxml/parserInternals.h>
51#include <libxml/hash.h>
52#ifdef LIBXML_XPTR_ENABLED
53#include <libxml/xpointer.h>
54#endif
55#ifdef LIBXML_DEBUG_ENABLED
56#include <libxml/debugXML.h>
57#endif
58#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000059#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000060#include <libxml/globals.h>
Daniel Veillard56de87e2005-02-16 00:22:29 +000061#ifdef LIBXML_PATTERN_ENABLED
62#include <libxml/pattern.h>
63#endif
64
Daniel Veillardade10f22012-07-12 09:43:27 +080065#include "buf.h"
66
Daniel Veillard56de87e2005-02-16 00:22:29 +000067#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000068#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000069#endif
Owen Taylor3473f882001-02-23 17:55:21 +000070
Daniel Veillard45490ae2008-07-29 09:13:19 +000071#define TODO \
Daniel Veillardd96f6d32003-10-07 21:25:12 +000072 xmlGenericError(xmlGenericErrorContext, \
73 "Unimplemented block at %s:%d\n", \
74 __FILE__, __LINE__);
75
Vojtech Fried3e031b72012-08-24 16:52:44 +080076/**
77 * WITH_TIM_SORT:
78 *
79 * Use the Timsort algorithm provided in timsort.h to sort
80 * nodeset as this is a great improvement over the old Shell sort
81 * used in xmlXPathNodeSetSort()
82 */
83#define WITH_TIM_SORT
84
William M. Brackd1757ab2004-10-02 22:07:48 +000085/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000086* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000087* If defined, this will use xmlXPathCmpNodesExt() instead of
88* xmlXPathCmpNodes(). The new function is optimized comparison of
89* non-element nodes; actually it will speed up comparison only if
90* xmlXPathOrderDocElems() was called in order to index the elements of
91* a tree in document order; Libxslt does such an indexing, thus it will
92* benefit from this optimization.
93*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000094#define XP_OPTIMIZED_NON_ELEM_COMPARISON
95
96/*
97* XP_OPTIMIZED_FILTER_FIRST:
98* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99* in a way, that it stop evaluation at the first node.
Daniel Veillard45490ae2008-07-29 09:13:19 +0000100*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000101#define XP_OPTIMIZED_FILTER_FIRST
102
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000103/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000104* XP_DEBUG_OBJ_USAGE:
105* Internal flag to enable tracking of how much XPath objects have been
106* created.
107*/
108/* #define XP_DEBUG_OBJ_USAGE */
109
110/*
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800111 * XPATH_MAX_STEPS:
112 * when compiling an XPath expression we arbitrary limit the maximum
113 * number of step operation in the compiled expression. 1000000 is
114 * an insanely large value which should never be reached under normal
115 * circumstances
116 */
117#define XPATH_MAX_STEPS 1000000
118
119/*
120 * XPATH_MAX_STACK_DEPTH:
121 * when evaluating an XPath expression we arbitrary limit the maximum
122 * number of object allowed to be pushed on the stack. 1000000 is
123 * an insanely large value which should never be reached under normal
124 * circumstances
125 */
126#define XPATH_MAX_STACK_DEPTH 1000000
127
128/*
129 * XPATH_MAX_NODESET_LENGTH:
130 * when evaluating an XPath expression nodesets are created and we
131 * arbitrary limit the maximum length of those node set. 10000000 is
132 * an insanely large value which should never be reached under normal
133 * circumstances, one would first need to construct an in memory tree
134 * with more than 10 millions nodes.
135 */
136#define XPATH_MAX_NODESET_LENGTH 10000000
137
138/*
William M. Brackd1757ab2004-10-02 22:07:48 +0000139 * TODO:
140 * There are a few spots where some tests are done which depend upon ascii
141 * data. These should be enhanced for full UTF8 support (see particularly
142 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
143 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000144
Denis Pauke28c8a12013-08-03 14:22:54 +0300145#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
146/**
147 * xmlXPathCmpNodesExt:
148 * @node1: the first node
149 * @node2: the second node
150 *
151 * Compare two nodes w.r.t document order.
152 * This one is optimized for handling of non-element nodes.
153 *
154 * Returns -2 in case of error 1 if first point < second point, 0 if
155 * it's the same node, -1 otherwise
156 */
157static int
158xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
159 int depth1, depth2;
160 int misc = 0, precedence1 = 0, precedence2 = 0;
161 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
162 xmlNodePtr cur, root;
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200163 ptrdiff_t l1, l2;
Denis Pauke28c8a12013-08-03 14:22:54 +0300164
165 if ((node1 == NULL) || (node2 == NULL))
166 return(-2);
167
168 if (node1 == node2)
169 return(0);
170
171 /*
172 * a couple of optimizations which will avoid computations in most cases
173 */
174 switch (node1->type) {
175 case XML_ELEMENT_NODE:
176 if (node2->type == XML_ELEMENT_NODE) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200177 if ((0 > (ptrdiff_t) node1->content) &&
178 (0 > (ptrdiff_t) node2->content) &&
Denis Pauke28c8a12013-08-03 14:22:54 +0300179 (node1->doc == node2->doc))
180 {
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200181 l1 = -((ptrdiff_t) node1->content);
182 l2 = -((ptrdiff_t) node2->content);
Denis Pauke28c8a12013-08-03 14:22:54 +0300183 if (l1 < l2)
184 return(1);
185 if (l1 > l2)
186 return(-1);
187 } else
188 goto turtle_comparison;
189 }
190 break;
191 case XML_ATTRIBUTE_NODE:
192 precedence1 = 1; /* element is owner */
193 miscNode1 = node1;
194 node1 = node1->parent;
195 misc = 1;
196 break;
197 case XML_TEXT_NODE:
198 case XML_CDATA_SECTION_NODE:
199 case XML_COMMENT_NODE:
200 case XML_PI_NODE: {
201 miscNode1 = node1;
202 /*
203 * Find nearest element node.
204 */
205 if (node1->prev != NULL) {
206 do {
207 node1 = node1->prev;
208 if (node1->type == XML_ELEMENT_NODE) {
209 precedence1 = 3; /* element in prev-sibl axis */
210 break;
211 }
212 if (node1->prev == NULL) {
213 precedence1 = 2; /* element is parent */
214 /*
215 * URGENT TODO: Are there any cases, where the
216 * parent of such a node is not an element node?
217 */
218 node1 = node1->parent;
219 break;
220 }
221 } while (1);
222 } else {
223 precedence1 = 2; /* element is parent */
224 node1 = node1->parent;
225 }
226 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200227 (0 <= (ptrdiff_t) node1->content)) {
Denis Pauke28c8a12013-08-03 14:22:54 +0300228 /*
229 * Fallback for whatever case.
230 */
231 node1 = miscNode1;
232 precedence1 = 0;
233 } else
234 misc = 1;
235 }
236 break;
237 case XML_NAMESPACE_DECL:
238 /*
239 * TODO: why do we return 1 for namespace nodes?
240 */
241 return(1);
242 default:
243 break;
244 }
245 switch (node2->type) {
246 case XML_ELEMENT_NODE:
247 break;
248 case XML_ATTRIBUTE_NODE:
249 precedence2 = 1; /* element is owner */
250 miscNode2 = node2;
251 node2 = node2->parent;
252 misc = 1;
253 break;
254 case XML_TEXT_NODE:
255 case XML_CDATA_SECTION_NODE:
256 case XML_COMMENT_NODE:
257 case XML_PI_NODE: {
258 miscNode2 = node2;
259 if (node2->prev != NULL) {
260 do {
261 node2 = node2->prev;
262 if (node2->type == XML_ELEMENT_NODE) {
263 precedence2 = 3; /* element in prev-sibl axis */
264 break;
265 }
266 if (node2->prev == NULL) {
267 precedence2 = 2; /* element is parent */
268 node2 = node2->parent;
269 break;
270 }
271 } while (1);
272 } else {
273 precedence2 = 2; /* element is parent */
274 node2 = node2->parent;
275 }
276 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200277 (0 <= (ptrdiff_t) node2->content))
Denis Pauke28c8a12013-08-03 14:22:54 +0300278 {
279 node2 = miscNode2;
280 precedence2 = 0;
281 } else
282 misc = 1;
283 }
284 break;
285 case XML_NAMESPACE_DECL:
286 return(1);
287 default:
288 break;
289 }
290 if (misc) {
291 if (node1 == node2) {
292 if (precedence1 == precedence2) {
293 /*
294 * The ugly case; but normally there aren't many
295 * adjacent non-element nodes around.
296 */
297 cur = miscNode2->prev;
298 while (cur != NULL) {
299 if (cur == miscNode1)
300 return(1);
301 if (cur->type == XML_ELEMENT_NODE)
302 return(-1);
303 cur = cur->prev;
304 }
305 return (-1);
306 } else {
307 /*
308 * Evaluate based on higher precedence wrt to the element.
309 * TODO: This assumes attributes are sorted before content.
310 * Is this 100% correct?
311 */
312 if (precedence1 < precedence2)
313 return(1);
314 else
315 return(-1);
316 }
317 }
318 /*
319 * Special case: One of the helper-elements is contained by the other.
320 * <foo>
321 * <node2>
322 * <node1>Text-1(precedence1 == 2)</node1>
323 * </node2>
324 * Text-6(precedence2 == 3)
325 * </foo>
326 */
327 if ((precedence2 == 3) && (precedence1 > 1)) {
328 cur = node1->parent;
329 while (cur) {
330 if (cur == node2)
331 return(1);
332 cur = cur->parent;
333 }
334 }
335 if ((precedence1 == 3) && (precedence2 > 1)) {
336 cur = node2->parent;
337 while (cur) {
338 if (cur == node1)
339 return(-1);
340 cur = cur->parent;
341 }
342 }
343 }
344
345 /*
346 * Speedup using document order if availble.
347 */
348 if ((node1->type == XML_ELEMENT_NODE) &&
349 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200350 (0 > (ptrdiff_t) node1->content) &&
351 (0 > (ptrdiff_t) node2->content) &&
Denis Pauke28c8a12013-08-03 14:22:54 +0300352 (node1->doc == node2->doc)) {
353
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200354 l1 = -((ptrdiff_t) node1->content);
355 l2 = -((ptrdiff_t) node2->content);
Denis Pauke28c8a12013-08-03 14:22:54 +0300356 if (l1 < l2)
357 return(1);
358 if (l1 > l2)
359 return(-1);
360 }
361
362turtle_comparison:
363
364 if (node1 == node2->prev)
365 return(1);
366 if (node1 == node2->next)
367 return(-1);
368 /*
369 * compute depth to root
370 */
Nick Wellnhofer3eaedba2015-07-11 14:27:34 +0200371 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
372 if (cur->parent == node1)
Denis Pauke28c8a12013-08-03 14:22:54 +0300373 return(1);
374 depth2++;
375 }
376 root = cur;
Nick Wellnhofer3eaedba2015-07-11 14:27:34 +0200377 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
378 if (cur->parent == node2)
Denis Pauke28c8a12013-08-03 14:22:54 +0300379 return(-1);
380 depth1++;
381 }
382 /*
383 * Distinct document (or distinct entities :-( ) case.
384 */
385 if (root != cur) {
386 return(-2);
387 }
388 /*
389 * get the nearest common ancestor.
390 */
391 while (depth1 > depth2) {
392 depth1--;
393 node1 = node1->parent;
394 }
395 while (depth2 > depth1) {
396 depth2--;
397 node2 = node2->parent;
398 }
399 while (node1->parent != node2->parent) {
400 node1 = node1->parent;
401 node2 = node2->parent;
402 /* should not happen but just in case ... */
403 if ((node1 == NULL) || (node2 == NULL))
404 return(-2);
405 }
406 /*
407 * Find who's first.
408 */
409 if (node1 == node2->prev)
410 return(1);
411 if (node1 == node2->next)
412 return(-1);
413 /*
414 * Speedup using document order if availble.
415 */
416 if ((node1->type == XML_ELEMENT_NODE) &&
417 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200418 (0 > (ptrdiff_t) node1->content) &&
419 (0 > (ptrdiff_t) node2->content) &&
Denis Pauke28c8a12013-08-03 14:22:54 +0300420 (node1->doc == node2->doc)) {
421
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200422 l1 = -((ptrdiff_t) node1->content);
423 l2 = -((ptrdiff_t) node2->content);
Denis Pauke28c8a12013-08-03 14:22:54 +0300424 if (l1 < l2)
425 return(1);
426 if (l1 > l2)
427 return(-1);
428 }
429
430 for (cur = node1->next;cur != NULL;cur = cur->next)
431 if (cur == node2)
432 return(1);
433 return(-1); /* assume there is no sibling list corruption */
434}
435#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
436
Vojtech Fried3e031b72012-08-24 16:52:44 +0800437/*
438 * Wrapper for the Timsort argorithm from timsort.h
439 */
440#ifdef WITH_TIM_SORT
441#define SORT_NAME libxml_domnode
442#define SORT_TYPE xmlNodePtr
443/**
444 * wrap_cmp:
445 * @x: a node
446 * @y: another node
447 *
448 * Comparison function for the Timsort implementation
449 *
Daniel Veillard510e7582012-09-04 11:50:36 +0800450 * Returns -2 in case of error -1 if first point < second point, 0 if
451 * it's the same node, +1 otherwise
Vojtech Fried3e031b72012-08-24 16:52:44 +0800452 */
453static
454int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
455#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Vojtech Fried3e031b72012-08-24 16:52:44 +0800456 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
457 {
458 int res = xmlXPathCmpNodesExt(x, y);
459 return res == -2 ? res : -res;
460 }
461#else
462 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463 {
464 int res = xmlXPathCmpNodes(x, y);
465 return res == -2 ? res : -res;
466 }
467#endif
468#define SORT_CMP(x, y) (wrap_cmp(x, y))
469#include "timsort.h"
470#endif /* WITH_TIM_SORT */
471
William M. Brack21e4ef22005-01-02 09:53:13 +0000472#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000473
474/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000475 * *
476 * Floating point stuff *
477 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000478 ************************************************************************/
479
Daniel Veillardc0631a62001-09-20 13:56:06 +0000480#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000481#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000482#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000483#include "trionan.c"
484
Owen Taylor3473f882001-02-23 17:55:21 +0000485/*
Owen Taylor3473f882001-02-23 17:55:21 +0000486 * The lack of portability of this section of the libc is annoying !
487 */
488double xmlXPathNAN = 0;
489double xmlXPathPINF = 1;
490double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000491static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000492static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000493
Owen Taylor3473f882001-02-23 17:55:21 +0000494/**
495 * xmlXPathInit:
496 *
497 * Initialize the XPath environment
498 */
499void
500xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000501 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000502
Bjorn Reese45029602001-08-21 09:23:53 +0000503 xmlXPathPINF = trio_pinf();
504 xmlXPathNINF = trio_ninf();
505 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000506 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000507
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000508 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000509}
510
Daniel Veillardcda96922001-08-21 10:56:31 +0000511/**
512 * xmlXPathIsNaN:
513 * @val: a double value
514 *
515 * Provides a portable isnan() function to detect whether a double
516 * is a NotaNumber. Based on trio code
517 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000518 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000519 * Returns 1 if the value is a NaN, 0 otherwise
520 */
521int
522xmlXPathIsNaN(double val) {
523 return(trio_isnan(val));
524}
525
526/**
527 * xmlXPathIsInf:
528 * @val: a double value
529 *
530 * Provides a portable isinf() function to detect whether a double
531 * is a +Infinite or -Infinite. Based on trio code
532 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000533 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000534 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
535 */
536int
537xmlXPathIsInf(double val) {
538 return(trio_isinf(val));
539}
540
Daniel Veillard4432df22003-09-28 18:58:27 +0000541#endif /* SCHEMAS or XPATH */
542#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000543/**
544 * xmlXPathGetSign:
545 * @val: a double value
546 *
547 * Provides a portable function to detect the sign of a double
548 * Modified from trio code
549 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000550 *
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000551 * Returns 1 if the value is Negative, 0 if positive
552 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000553static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000554xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000555 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000556}
557
558
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000559/*
560 * TODO: when compatibility allows remove all "fake node libxslt" strings
561 * the test should just be name[0] = ' '
562 */
Daniel Veillard074f37e2008-09-01 13:38:22 +0000563#ifdef DEBUG_XPATH_EXPRESSION
564#define DEBUG_STEP
565#define DEBUG_EXPR
566#define DEBUG_EVAL_COUNTS
567#endif
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000568
569static xmlNs xmlXPathXMLNamespaceStruct = {
570 NULL,
571 XML_NAMESPACE_DECL,
572 XML_XML_NAMESPACE,
573 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000574 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000575 NULL
576};
577static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
578#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard45490ae2008-07-29 09:13:19 +0000579/*
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000580 * Optimizer is disabled only when threaded apps are detected while
581 * the library ain't compiled for thread safety.
582 */
583static int xmlXPathDisableOptimizer = 0;
584#endif
585
Owen Taylor3473f882001-02-23 17:55:21 +0000586/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000587 * *
588 * Error handling routines *
589 * *
590 ************************************************************************/
591
Daniel Veillard24505b02005-07-28 23:49:35 +0000592/**
593 * XP_ERRORNULL:
594 * @X: the error code
595 *
596 * Macro to raise an XPath error and return NULL.
597 */
598#define XP_ERRORNULL(X) \
599 { xmlXPathErr(ctxt, X); return(NULL); }
600
William M. Brack08171912003-12-29 02:52:11 +0000601/*
602 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
603 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000604static const char *xmlXPathErrorMessages[] = {
605 "Ok\n",
606 "Number encoding\n",
607 "Unfinished literal\n",
608 "Start of literal\n",
609 "Expected $ for variable reference\n",
610 "Undefined variable\n",
611 "Invalid predicate\n",
612 "Invalid expression\n",
613 "Missing closing curly brace\n",
614 "Unregistered function\n",
615 "Invalid operand\n",
616 "Invalid type\n",
617 "Invalid number of arguments\n",
618 "Invalid context size\n",
619 "Invalid context position\n",
620 "Memory allocation error\n",
621 "Syntax error\n",
622 "Resource error\n",
623 "Sub resource error\n",
624 "Undefined namespace prefix\n",
625 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000626 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000627 "Invalid or incomplete context\n",
Jan Pokorný75801652013-12-19 15:09:14 +0100628 "Stack usage error\n",
Daniel Veillard47881282012-09-07 14:24:50 +0800629 "Forbidden variable\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000630 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000631};
William M. Brackcd65bc92005-01-06 09:39:18 +0000632#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
633 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000634/**
635 * xmlXPathErrMemory:
636 * @ctxt: an XPath context
637 * @extra: extra informations
638 *
639 * Handle a redefinition of attribute error
640 */
641static void
642xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
643{
644 if (ctxt != NULL) {
645 if (extra) {
646 xmlChar buf[200];
647
648 xmlStrPrintf(buf, 200,
David Kilzer4472c3a2016-05-13 15:13:17 +0800649 "Memory allocation failed : %s\n",
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000650 extra);
651 ctxt->lastError.message = (char *) xmlStrdup(buf);
652 } else {
653 ctxt->lastError.message = (char *)
654 xmlStrdup(BAD_CAST "Memory allocation failed\n");
655 }
656 ctxt->lastError.domain = XML_FROM_XPATH;
657 ctxt->lastError.code = XML_ERR_NO_MEMORY;
658 if (ctxt->error != NULL)
659 ctxt->error(ctxt->userData, &ctxt->lastError);
660 } else {
661 if (extra)
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 extra, NULL, NULL, 0, 0,
666 "Memory allocation failed : %s\n", extra);
667 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000668 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000669 NULL, NULL, XML_FROM_XPATH,
670 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
671 NULL, NULL, NULL, 0, 0,
672 "Memory allocation failed\n");
673 }
674}
675
676/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000677 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000678 * @ctxt: an XPath parser context
679 * @extra: extra informations
680 *
681 * Handle a redefinition of attribute error
682 */
683static void
684xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
685{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000686 if (ctxt == NULL)
687 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000688 else {
689 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000690 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000691 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000692}
693
694/**
695 * xmlXPathErr:
696 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000697 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000698 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000699 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000700 */
701void
702xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
703{
William M. Brackcd65bc92005-01-06 09:39:18 +0000704 if ((error < 0) || (error > MAXERRNO))
705 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000706 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000707 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000708 NULL, NULL, XML_FROM_XPATH,
709 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
710 XML_ERR_ERROR, NULL, 0,
711 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200712 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000713 return;
714 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000715 ctxt->error = error;
716 if (ctxt->context == NULL) {
717 __xmlRaiseError(NULL, NULL, NULL,
718 NULL, NULL, XML_FROM_XPATH,
719 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
720 XML_ERR_ERROR, NULL, 0,
721 (const char *) ctxt->base, NULL, NULL,
722 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200723 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000724 return;
725 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000726
727 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000728 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000729
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000730 ctxt->context->lastError.domain = XML_FROM_XPATH;
731 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
732 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000733 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000734 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
735 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
736 ctxt->context->lastError.node = ctxt->context->debugNode;
737 if (ctxt->context->error != NULL) {
738 ctxt->context->error(ctxt->context->userData,
739 &ctxt->context->lastError);
740 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000741 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000742 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
743 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
744 XML_ERR_ERROR, NULL, 0,
745 (const char *) ctxt->base, NULL, NULL,
746 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200747 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000748 }
749
750}
751
752/**
753 * xmlXPatherror:
754 * @ctxt: the XPath Parser context
755 * @file: the file name
756 * @line: the line number
757 * @no: the error number
758 *
759 * Formats an error message.
760 */
761void
762xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
763 int line ATTRIBUTE_UNUSED, int no) {
764 xmlXPathErr(ctxt, no);
765}
766
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000767/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000768 * *
769 * Utilities *
770 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000771 ************************************************************************/
772
773/**
774 * xsltPointerList:
775 *
776 * Pointer-list for various purposes.
777 */
778typedef struct _xmlPointerList xmlPointerList;
779typedef xmlPointerList *xmlPointerListPtr;
780struct _xmlPointerList {
781 void **items;
782 int number;
783 int size;
784};
785/*
786* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
787* and here, we should make the functions public.
788*/
789static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000790xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000791 void *item,
792 int initialSize)
793{
794 if (list->items == NULL) {
795 if (initialSize <= 0)
796 initialSize = 1;
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800797 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000798 if (list->items == NULL) {
799 xmlXPathErrMemory(NULL,
800 "xmlPointerListCreate: allocating item\n");
801 return(-1);
802 }
803 list->number = 0;
804 list->size = initialSize;
805 } else if (list->size <= list->number) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800806 if (list->size > 50000000) {
807 xmlXPathErrMemory(NULL,
808 "xmlPointerListAddSize: re-allocating item\n");
809 return(-1);
810 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000811 list->size *= 2;
812 list->items = (void **) xmlRealloc(list->items,
813 list->size * sizeof(void *));
814 if (list->items == NULL) {
815 xmlXPathErrMemory(NULL,
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800816 "xmlPointerListAddSize: re-allocating item\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000817 list->size = 0;
818 return(-1);
819 }
820 }
821 list->items[list->number++] = item;
822 return(0);
823}
824
825/**
826 * xsltPointerListCreate:
827 *
828 * Creates an xsltPointerList structure.
829 *
830 * Returns a xsltPointerList structure or NULL in case of an error.
831 */
832static xmlPointerListPtr
833xmlPointerListCreate(int initialSize)
834{
835 xmlPointerListPtr ret;
836
837 ret = xmlMalloc(sizeof(xmlPointerList));
838 if (ret == NULL) {
839 xmlXPathErrMemory(NULL,
840 "xmlPointerListCreate: allocating item\n");
841 return (NULL);
842 }
843 memset(ret, 0, sizeof(xmlPointerList));
844 if (initialSize > 0) {
845 xmlPointerListAddSize(ret, NULL, initialSize);
846 ret->number = 0;
847 }
848 return (ret);
849}
850
851/**
852 * xsltPointerListFree:
853 *
854 * Frees the xsltPointerList structure. This does not free
855 * the content of the list.
856 */
857static void
858xmlPointerListFree(xmlPointerListPtr list)
859{
860 if (list == NULL)
861 return;
862 if (list->items != NULL)
863 xmlFree(list->items);
864 xmlFree(list);
865}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000866
867/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000868 * *
869 * Parser Types *
870 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000871 ************************************************************************/
872
873/*
874 * Types are private:
875 */
876
877typedef enum {
878 XPATH_OP_END=0,
879 XPATH_OP_AND,
880 XPATH_OP_OR,
881 XPATH_OP_EQUAL,
882 XPATH_OP_CMP,
883 XPATH_OP_PLUS,
884 XPATH_OP_MULT,
885 XPATH_OP_UNION,
886 XPATH_OP_ROOT,
887 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000888 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000889 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000890 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000891 XPATH_OP_VARIABLE,
892 XPATH_OP_FUNCTION,
893 XPATH_OP_ARG,
894 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000895 XPATH_OP_FILTER, /* 17 */
896 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000897#ifdef LIBXML_XPTR_ENABLED
898 ,XPATH_OP_RANGETO
899#endif
900} xmlXPathOp;
901
902typedef enum {
903 AXIS_ANCESTOR = 1,
904 AXIS_ANCESTOR_OR_SELF,
905 AXIS_ATTRIBUTE,
906 AXIS_CHILD,
907 AXIS_DESCENDANT,
908 AXIS_DESCENDANT_OR_SELF,
909 AXIS_FOLLOWING,
910 AXIS_FOLLOWING_SIBLING,
911 AXIS_NAMESPACE,
912 AXIS_PARENT,
913 AXIS_PRECEDING,
914 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000915 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000916} xmlXPathAxisVal;
917
918typedef enum {
919 NODE_TEST_NONE = 0,
920 NODE_TEST_TYPE = 1,
921 NODE_TEST_PI = 2,
922 NODE_TEST_ALL = 3,
923 NODE_TEST_NS = 4,
924 NODE_TEST_NAME = 5
925} xmlXPathTestVal;
926
927typedef enum {
928 NODE_TYPE_NODE = 0,
929 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
930 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000931 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000932} xmlXPathTypeVal;
933
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000934typedef struct _xmlXPathStepOp xmlXPathStepOp;
935typedef xmlXPathStepOp *xmlXPathStepOpPtr;
936struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000937 xmlXPathOp op; /* The identifier of the operation */
938 int ch1; /* First child */
939 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000940 int value;
941 int value2;
942 int value3;
943 void *value4;
944 void *value5;
Nick Wellnhofer229d1f92016-08-22 13:21:57 +0200945 xmlXPathFunction cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000946 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000947};
948
949struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000950 int nbStep; /* Number of steps in this expression */
951 int maxStep; /* Maximum number of steps allocated */
952 xmlXPathStepOp *steps; /* ops for computation of this expression */
953 int last; /* index of last step in expression */
954 xmlChar *expr; /* the expression being computed */
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200955 xmlDictPtr dict; /* the dictionary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000956#ifdef DEBUG_EVAL_COUNTS
957 int nb;
958 xmlChar *string;
959#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000960#ifdef XPATH_STREAMING
961 xmlPatternPtr stream;
962#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000963};
964
965/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000966 * *
967 * Forward declarations *
968 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000969 ************************************************************************/
970static void
971xmlXPathFreeValueTree(xmlNodeSetPtr obj);
972static void
973xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
974static int
975xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
976 xmlXPathStepOpPtr op, xmlNodePtr *first);
977static int
978xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000979 xmlXPathStepOpPtr op,
980 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000981
982/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000983 * *
984 * Parser Type functions *
985 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000986 ************************************************************************/
987
988/**
989 * xmlXPathNewCompExpr:
990 *
991 * Create a new Xpath component
992 *
993 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
994 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000995static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000996xmlXPathNewCompExpr(void) {
997 xmlXPathCompExprPtr cur;
998
999 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1000 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001001 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001002 return(NULL);
1003 }
1004 memset(cur, 0, sizeof(xmlXPathCompExpr));
1005 cur->maxStep = 10;
1006 cur->nbStep = 0;
1007 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1008 sizeof(xmlXPathStepOp));
1009 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001010 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001011 xmlFree(cur);
1012 return(NULL);
1013 }
1014 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1015 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +00001016#ifdef DEBUG_EVAL_COUNTS
1017 cur->nb = 0;
1018#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001019 return(cur);
1020}
1021
1022/**
1023 * xmlXPathFreeCompExpr:
1024 * @comp: an XPATH comp
1025 *
1026 * Free up the memory allocated by @comp
1027 */
1028void
Daniel Veillardf06307e2001-07-03 10:35:50 +00001029xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1030{
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001031 xmlXPathStepOpPtr op;
1032 int i;
1033
1034 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00001035 return;
Daniel Veillard4773df22004-01-23 13:15:13 +00001036 if (comp->dict == NULL) {
1037 for (i = 0; i < comp->nbStep; i++) {
1038 op = &comp->steps[i];
1039 if (op->value4 != NULL) {
1040 if (op->op == XPATH_OP_VALUE)
1041 xmlXPathFreeObject(op->value4);
1042 else
1043 xmlFree(op->value4);
1044 }
1045 if (op->value5 != NULL)
1046 xmlFree(op->value5);
1047 }
1048 } else {
1049 for (i = 0; i < comp->nbStep; i++) {
1050 op = &comp->steps[i];
1051 if (op->value4 != NULL) {
1052 if (op->op == XPATH_OP_VALUE)
1053 xmlXPathFreeObject(op->value4);
1054 }
1055 }
1056 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001057 }
1058 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00001059 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001060 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001061#ifdef DEBUG_EVAL_COUNTS
1062 if (comp->string != NULL) {
1063 xmlFree(comp->string);
1064 }
1065#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +00001066#ifdef XPATH_STREAMING
1067 if (comp->stream != NULL) {
1068 xmlFreePatternList(comp->stream);
1069 }
1070#endif
Daniel Veillard118aed72002-09-24 14:13:13 +00001071 if (comp->expr != NULL) {
1072 xmlFree(comp->expr);
1073 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001074
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001075 xmlFree(comp);
1076}
1077
1078/**
1079 * xmlXPathCompExprAdd:
1080 * @comp: the compiled expression
1081 * @ch1: first child index
1082 * @ch2: second child index
1083 * @op: an op
1084 * @value: the first int value
1085 * @value2: the second int value
1086 * @value3: the third int value
1087 * @value4: the first string value
1088 * @value5: the second string value
1089 *
William M. Brack08171912003-12-29 02:52:11 +00001090 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001091 *
1092 * Returns -1 in case of failure, the index otherwise
1093 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001094static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001095xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1096 xmlXPathOp op, int value,
1097 int value2, int value3, void *value4, void *value5) {
1098 if (comp->nbStep >= comp->maxStep) {
1099 xmlXPathStepOp *real;
1100
Daniel Veillardcd852ad2012-07-30 10:12:18 +08001101 if (comp->maxStep >= XPATH_MAX_STEPS) {
1102 xmlXPathErrMemory(NULL, "adding step\n");
1103 return(-1);
1104 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001105 comp->maxStep *= 2;
1106 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1107 comp->maxStep * sizeof(xmlXPathStepOp));
1108 if (real == NULL) {
1109 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001110 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001111 return(-1);
1112 }
1113 comp->steps = real;
1114 }
1115 comp->last = comp->nbStep;
1116 comp->steps[comp->nbStep].ch1 = ch1;
1117 comp->steps[comp->nbStep].ch2 = ch2;
1118 comp->steps[comp->nbStep].op = op;
1119 comp->steps[comp->nbStep].value = value;
1120 comp->steps[comp->nbStep].value2 = value2;
1121 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +00001122 if ((comp->dict != NULL) &&
1123 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1124 (op == XPATH_OP_COLLECT))) {
1125 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001126 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001127 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001128 xmlFree(value4);
1129 } else
1130 comp->steps[comp->nbStep].value4 = NULL;
1131 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001132 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001133 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001134 xmlFree(value5);
1135 } else
1136 comp->steps[comp->nbStep].value5 = NULL;
1137 } else {
1138 comp->steps[comp->nbStep].value4 = value4;
1139 comp->steps[comp->nbStep].value5 = value5;
1140 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00001141 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001142 return(comp->nbStep++);
1143}
1144
Daniel Veillardf06307e2001-07-03 10:35:50 +00001145/**
1146 * xmlXPathCompSwap:
1147 * @comp: the compiled expression
1148 * @op: operation index
1149 *
1150 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +00001151 */
1152static void
1153xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1154 int tmp;
1155
Daniel Veillardbc6f7592002-04-16 07:49:59 +00001156#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +00001157 /*
1158 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +00001159 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +00001160 * application
1161 */
1162 if (xmlXPathDisableOptimizer)
1163 return;
1164#endif
1165
Daniel Veillardf06307e2001-07-03 10:35:50 +00001166 tmp = op->ch1;
1167 op->ch1 = op->ch2;
1168 op->ch2 = tmp;
1169}
1170
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001171#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1172 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1173 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001174#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1175 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1176 (op), (val), (val2), (val3), (val4), (val5))
1177
Daniel Veillard45490ae2008-07-29 09:13:19 +00001178#define PUSH_LEAVE_EXPR(op, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001179xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1180
Daniel Veillard45490ae2008-07-29 09:13:19 +00001181#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001182xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1183
Daniel Veillard45490ae2008-07-29 09:13:19 +00001184#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +00001185xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1186 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001187
1188/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +00001189 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001190 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001191 * *
1192 ************************************************************************/
1193
1194/* #define XP_DEFAULT_CACHE_ON */
1195
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001196#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001197
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001198typedef struct _xmlXPathContextCache xmlXPathContextCache;
1199typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1200struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00001201 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1202 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1203 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1204 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1205 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001206 int maxNodeset;
1207 int maxString;
1208 int maxBoolean;
1209 int maxNumber;
1210 int maxMisc;
1211#ifdef XP_DEBUG_OBJ_USAGE
1212 int dbgCachedAll;
1213 int dbgCachedNodeset;
1214 int dbgCachedString;
1215 int dbgCachedBool;
1216 int dbgCachedNumber;
1217 int dbgCachedPoint;
1218 int dbgCachedRange;
1219 int dbgCachedLocset;
1220 int dbgCachedUsers;
1221 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001222 int dbgCachedUndefined;
1223
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001224
1225 int dbgReusedAll;
1226 int dbgReusedNodeset;
1227 int dbgReusedString;
1228 int dbgReusedBool;
1229 int dbgReusedNumber;
1230 int dbgReusedPoint;
1231 int dbgReusedRange;
1232 int dbgReusedLocset;
1233 int dbgReusedUsers;
1234 int dbgReusedXSLTTree;
1235 int dbgReusedUndefined;
1236
1237#endif
1238};
1239
1240/************************************************************************
1241 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001242 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +00001243 * *
1244 ************************************************************************/
1245
Daniel Veillard45490ae2008-07-29 09:13:19 +00001246#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +00001247 xmlGenericError(xmlGenericErrorContext, \
1248 "Internal error at %s:%d\n", \
1249 __FILE__, __LINE__);
1250
1251#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001252static void
1253xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001254 int i;
1255 char shift[100];
1256
1257 for (i = 0;((i < depth) && (i < 25));i++)
1258 shift[2 * i] = shift[2 * i + 1] = ' ';
1259 shift[2 * i] = shift[2 * i + 1] = 0;
1260 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001261 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001262 fprintf(output, "Node is NULL !\n");
1263 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001264
Owen Taylor3473f882001-02-23 17:55:21 +00001265 }
1266
1267 if ((cur->type == XML_DOCUMENT_NODE) ||
1268 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001269 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001270 fprintf(output, " /\n");
1271 } else if (cur->type == XML_ATTRIBUTE_NODE)
1272 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1273 else
1274 xmlDebugDumpOneNode(output, cur, depth);
1275}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001276static void
1277xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001278 xmlNodePtr tmp;
1279 int i;
1280 char shift[100];
1281
1282 for (i = 0;((i < depth) && (i < 25));i++)
1283 shift[2 * i] = shift[2 * i + 1] = ' ';
1284 shift[2 * i] = shift[2 * i + 1] = 0;
1285 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001286 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001287 fprintf(output, "Node is NULL !\n");
1288 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001289
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001290 }
1291
1292 while (cur != NULL) {
1293 tmp = cur;
1294 cur = cur->next;
1295 xmlDebugDumpOneNode(output, tmp, depth);
1296 }
1297}
Owen Taylor3473f882001-02-23 17:55:21 +00001298
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001299static void
1300xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001301 int i;
1302 char shift[100];
1303
1304 for (i = 0;((i < depth) && (i < 25));i++)
1305 shift[2 * i] = shift[2 * i + 1] = ' ';
1306 shift[2 * i] = shift[2 * i + 1] = 0;
1307
1308 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001309 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001310 fprintf(output, "NodeSet is NULL !\n");
1311 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001312
Owen Taylor3473f882001-02-23 17:55:21 +00001313 }
1314
Daniel Veillard911f49a2001-04-07 15:39:35 +00001315 if (cur != NULL) {
1316 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1317 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001318 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +00001319 fprintf(output, "%d", i + 1);
1320 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1321 }
Owen Taylor3473f882001-02-23 17:55:21 +00001322 }
1323}
1324
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001325static void
1326xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001327 int i;
1328 char shift[100];
1329
1330 for (i = 0;((i < depth) && (i < 25));i++)
1331 shift[2 * i] = shift[2 * i + 1] = ' ';
1332 shift[2 * i] = shift[2 * i + 1] = 0;
1333
1334 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001335 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001336 fprintf(output, "Value Tree is NULL !\n");
1337 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001338
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001339 }
1340
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001341 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001342 fprintf(output, "%d", i + 1);
1343 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1344}
Owen Taylor3473f882001-02-23 17:55:21 +00001345#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001346static void
1347xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001348 int i;
1349 char shift[100];
1350
1351 for (i = 0;((i < depth) && (i < 25));i++)
1352 shift[2 * i] = shift[2 * i + 1] = ' ';
1353 shift[2 * i] = shift[2 * i + 1] = 0;
1354
1355 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001356 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001357 fprintf(output, "LocationSet is NULL !\n");
1358 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001359
Owen Taylor3473f882001-02-23 17:55:21 +00001360 }
1361
1362 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001363 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001364 fprintf(output, "%d : ", i + 1);
1365 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1366 }
1367}
Daniel Veillard017b1082001-06-21 11:20:21 +00001368#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001369
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00001370/**
1371 * xmlXPathDebugDumpObject:
1372 * @output: the FILE * to dump the output
1373 * @cur: the object to inspect
1374 * @depth: indentation level
1375 *
1376 * Dump the content of the object for debugging purposes
1377 */
1378void
1379xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001380 int i;
1381 char shift[100];
1382
Daniel Veillarda82b1822004-11-08 16:24:57 +00001383 if (output == NULL) return;
1384
Owen Taylor3473f882001-02-23 17:55:21 +00001385 for (i = 0;((i < depth) && (i < 25));i++)
1386 shift[2 * i] = shift[2 * i + 1] = ' ';
1387 shift[2 * i] = shift[2 * i + 1] = 0;
1388
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001389
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001390 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001391
1392 if (cur == NULL) {
1393 fprintf(output, "Object is empty (NULL)\n");
1394 return;
1395 }
1396 switch(cur->type) {
1397 case XPATH_UNDEFINED:
1398 fprintf(output, "Object is uninitialized\n");
1399 break;
1400 case XPATH_NODESET:
1401 fprintf(output, "Object is a Node Set :\n");
1402 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1403 break;
1404 case XPATH_XSLT_TREE:
1405 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001406 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001407 break;
1408 case XPATH_BOOLEAN:
1409 fprintf(output, "Object is a Boolean : ");
1410 if (cur->boolval) fprintf(output, "true\n");
1411 else fprintf(output, "false\n");
1412 break;
1413 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001414 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001415 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001416 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001417 break;
1418 case -1:
1419 fprintf(output, "Object is a number : -Infinity\n");
1420 break;
1421 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001422 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001423 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001424 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1425 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001426 } else {
1427 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1428 }
1429 }
Owen Taylor3473f882001-02-23 17:55:21 +00001430 break;
1431 case XPATH_STRING:
1432 fprintf(output, "Object is a string : ");
1433 xmlDebugDumpString(output, cur->stringval);
1434 fprintf(output, "\n");
1435 break;
1436 case XPATH_POINT:
1437 fprintf(output, "Object is a point : index %d in node", cur->index);
1438 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1439 fprintf(output, "\n");
1440 break;
1441 case XPATH_RANGE:
1442 if ((cur->user2 == NULL) ||
1443 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1444 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001445 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001446 if (cur->index >= 0)
1447 fprintf(output, "index %d in ", cur->index);
1448 fprintf(output, "node\n");
1449 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1450 depth + 1);
1451 } else {
1452 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001453 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001454 fprintf(output, "From ");
1455 if (cur->index >= 0)
1456 fprintf(output, "index %d in ", cur->index);
1457 fprintf(output, "node\n");
1458 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1459 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001460 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001461 fprintf(output, "To ");
1462 if (cur->index2 >= 0)
1463 fprintf(output, "index %d in ", cur->index2);
1464 fprintf(output, "node\n");
1465 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1466 depth + 1);
1467 fprintf(output, "\n");
1468 }
1469 break;
1470 case XPATH_LOCATIONSET:
1471#if defined(LIBXML_XPTR_ENABLED)
1472 fprintf(output, "Object is a Location Set:\n");
1473 xmlXPathDebugDumpLocationSet(output,
1474 (xmlLocationSetPtr) cur->user, depth);
1475#endif
1476 break;
1477 case XPATH_USERS:
1478 fprintf(output, "Object is user defined\n");
1479 break;
1480 }
1481}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001482
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001483static void
1484xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001485 xmlXPathStepOpPtr op, int depth) {
1486 int i;
1487 char shift[100];
1488
1489 for (i = 0;((i < depth) && (i < 25));i++)
1490 shift[2 * i] = shift[2 * i + 1] = ' ';
1491 shift[2 * i] = shift[2 * i + 1] = 0;
1492
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001493 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001494 if (op == NULL) {
1495 fprintf(output, "Step is NULL\n");
1496 return;
1497 }
1498 switch (op->op) {
1499 case XPATH_OP_END:
1500 fprintf(output, "END"); break;
1501 case XPATH_OP_AND:
1502 fprintf(output, "AND"); break;
1503 case XPATH_OP_OR:
1504 fprintf(output, "OR"); break;
1505 case XPATH_OP_EQUAL:
1506 if (op->value)
1507 fprintf(output, "EQUAL =");
1508 else
1509 fprintf(output, "EQUAL !=");
1510 break;
1511 case XPATH_OP_CMP:
1512 if (op->value)
1513 fprintf(output, "CMP <");
1514 else
1515 fprintf(output, "CMP >");
1516 if (!op->value2)
1517 fprintf(output, "=");
1518 break;
1519 case XPATH_OP_PLUS:
1520 if (op->value == 0)
1521 fprintf(output, "PLUS -");
1522 else if (op->value == 1)
1523 fprintf(output, "PLUS +");
1524 else if (op->value == 2)
1525 fprintf(output, "PLUS unary -");
1526 else if (op->value == 3)
1527 fprintf(output, "PLUS unary - -");
1528 break;
1529 case XPATH_OP_MULT:
1530 if (op->value == 0)
1531 fprintf(output, "MULT *");
1532 else if (op->value == 1)
1533 fprintf(output, "MULT div");
1534 else
1535 fprintf(output, "MULT mod");
1536 break;
1537 case XPATH_OP_UNION:
1538 fprintf(output, "UNION"); break;
1539 case XPATH_OP_ROOT:
1540 fprintf(output, "ROOT"); break;
1541 case XPATH_OP_NODE:
1542 fprintf(output, "NODE"); break;
1543 case XPATH_OP_RESET:
1544 fprintf(output, "RESET"); break;
1545 case XPATH_OP_SORT:
1546 fprintf(output, "SORT"); break;
1547 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001548 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1549 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1550 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001551 const xmlChar *prefix = op->value4;
1552 const xmlChar *name = op->value5;
1553
1554 fprintf(output, "COLLECT ");
1555 switch (axis) {
1556 case AXIS_ANCESTOR:
1557 fprintf(output, " 'ancestors' "); break;
1558 case AXIS_ANCESTOR_OR_SELF:
1559 fprintf(output, " 'ancestors-or-self' "); break;
1560 case AXIS_ATTRIBUTE:
1561 fprintf(output, " 'attributes' "); break;
1562 case AXIS_CHILD:
1563 fprintf(output, " 'child' "); break;
1564 case AXIS_DESCENDANT:
1565 fprintf(output, " 'descendant' "); break;
1566 case AXIS_DESCENDANT_OR_SELF:
1567 fprintf(output, " 'descendant-or-self' "); break;
1568 case AXIS_FOLLOWING:
1569 fprintf(output, " 'following' "); break;
1570 case AXIS_FOLLOWING_SIBLING:
1571 fprintf(output, " 'following-siblings' "); break;
1572 case AXIS_NAMESPACE:
1573 fprintf(output, " 'namespace' "); break;
1574 case AXIS_PARENT:
1575 fprintf(output, " 'parent' "); break;
1576 case AXIS_PRECEDING:
1577 fprintf(output, " 'preceding' "); break;
1578 case AXIS_PRECEDING_SIBLING:
1579 fprintf(output, " 'preceding-sibling' "); break;
1580 case AXIS_SELF:
1581 fprintf(output, " 'self' "); break;
1582 }
1583 switch (test) {
1584 case NODE_TEST_NONE:
1585 fprintf(output, "'none' "); break;
1586 case NODE_TEST_TYPE:
1587 fprintf(output, "'type' "); break;
1588 case NODE_TEST_PI:
1589 fprintf(output, "'PI' "); break;
1590 case NODE_TEST_ALL:
1591 fprintf(output, "'all' "); break;
1592 case NODE_TEST_NS:
1593 fprintf(output, "'namespace' "); break;
1594 case NODE_TEST_NAME:
1595 fprintf(output, "'name' "); break;
1596 }
1597 switch (type) {
1598 case NODE_TYPE_NODE:
1599 fprintf(output, "'node' "); break;
1600 case NODE_TYPE_COMMENT:
1601 fprintf(output, "'comment' "); break;
1602 case NODE_TYPE_TEXT:
1603 fprintf(output, "'text' "); break;
1604 case NODE_TYPE_PI:
1605 fprintf(output, "'PI' "); break;
1606 }
1607 if (prefix != NULL)
1608 fprintf(output, "%s:", prefix);
1609 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001610 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001611 break;
1612
1613 }
1614 case XPATH_OP_VALUE: {
1615 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1616
1617 fprintf(output, "ELEM ");
1618 xmlXPathDebugDumpObject(output, object, 0);
1619 goto finish;
1620 }
1621 case XPATH_OP_VARIABLE: {
1622 const xmlChar *prefix = op->value5;
1623 const xmlChar *name = op->value4;
1624
1625 if (prefix != NULL)
1626 fprintf(output, "VARIABLE %s:%s", prefix, name);
1627 else
1628 fprintf(output, "VARIABLE %s", name);
1629 break;
1630 }
1631 case XPATH_OP_FUNCTION: {
1632 int nbargs = op->value;
1633 const xmlChar *prefix = op->value5;
1634 const xmlChar *name = op->value4;
1635
1636 if (prefix != NULL)
1637 fprintf(output, "FUNCTION %s:%s(%d args)",
1638 prefix, name, nbargs);
1639 else
1640 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1641 break;
1642 }
1643 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1644 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001645 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001646#ifdef LIBXML_XPTR_ENABLED
1647 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1648#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001649 default:
1650 fprintf(output, "UNKNOWN %d\n", op->op); return;
1651 }
1652 fprintf(output, "\n");
1653finish:
1654 if (op->ch1 >= 0)
1655 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1656 if (op->ch2 >= 0)
1657 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1658}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001659
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001660/**
1661 * xmlXPathDebugDumpCompExpr:
1662 * @output: the FILE * for the output
1663 * @comp: the precompiled XPath expression
1664 * @depth: the indentation level.
1665 *
1666 * Dumps the tree of the compiled XPath expression.
1667 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001668void
1669xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1670 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001671 int i;
1672 char shift[100];
1673
Daniel Veillarda82b1822004-11-08 16:24:57 +00001674 if ((output == NULL) || (comp == NULL)) return;
1675
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001676 for (i = 0;((i < depth) && (i < 25));i++)
1677 shift[2 * i] = shift[2 * i + 1] = ' ';
1678 shift[2 * i] = shift[2 * i + 1] = 0;
1679
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001680 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001681
Nick Wellnhoferca8635b2017-09-07 15:46:12 +02001682#ifdef XPATH_STREAMING
1683 if (comp->stream) {
1684 fprintf(output, "Streaming Expression\n");
1685 } else
1686#endif
1687 {
1688 fprintf(output, "Compiled Expression : %d elements\n",
1689 comp->nbStep);
1690 i = comp->last;
1691 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1692 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001693}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001694
1695#ifdef XP_DEBUG_OBJ_USAGE
1696
1697/*
1698* XPath object usage related debugging variables.
1699*/
1700static int xmlXPathDebugObjCounterUndefined = 0;
1701static int xmlXPathDebugObjCounterNodeset = 0;
1702static int xmlXPathDebugObjCounterBool = 0;
1703static int xmlXPathDebugObjCounterNumber = 0;
1704static int xmlXPathDebugObjCounterString = 0;
1705static int xmlXPathDebugObjCounterPoint = 0;
1706static int xmlXPathDebugObjCounterRange = 0;
1707static int xmlXPathDebugObjCounterLocset = 0;
1708static int xmlXPathDebugObjCounterUsers = 0;
1709static int xmlXPathDebugObjCounterXSLTTree = 0;
1710static int xmlXPathDebugObjCounterAll = 0;
1711
1712static int xmlXPathDebugObjTotalUndefined = 0;
1713static int xmlXPathDebugObjTotalNodeset = 0;
1714static int xmlXPathDebugObjTotalBool = 0;
1715static int xmlXPathDebugObjTotalNumber = 0;
1716static int xmlXPathDebugObjTotalString = 0;
1717static int xmlXPathDebugObjTotalPoint = 0;
1718static int xmlXPathDebugObjTotalRange = 0;
1719static int xmlXPathDebugObjTotalLocset = 0;
1720static int xmlXPathDebugObjTotalUsers = 0;
1721static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001722static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001723
1724static int xmlXPathDebugObjMaxUndefined = 0;
1725static int xmlXPathDebugObjMaxNodeset = 0;
1726static int xmlXPathDebugObjMaxBool = 0;
1727static int xmlXPathDebugObjMaxNumber = 0;
1728static int xmlXPathDebugObjMaxString = 0;
1729static int xmlXPathDebugObjMaxPoint = 0;
1730static int xmlXPathDebugObjMaxRange = 0;
1731static int xmlXPathDebugObjMaxLocset = 0;
1732static int xmlXPathDebugObjMaxUsers = 0;
1733static int xmlXPathDebugObjMaxXSLTTree = 0;
1734static int xmlXPathDebugObjMaxAll = 0;
1735
1736/* REVISIT TODO: Make this static when committing */
1737static void
1738xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1739{
1740 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001741 if (ctxt->cache != NULL) {
1742 xmlXPathContextCachePtr cache =
1743 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001744
1745 cache->dbgCachedAll = 0;
1746 cache->dbgCachedNodeset = 0;
1747 cache->dbgCachedString = 0;
1748 cache->dbgCachedBool = 0;
1749 cache->dbgCachedNumber = 0;
1750 cache->dbgCachedPoint = 0;
1751 cache->dbgCachedRange = 0;
1752 cache->dbgCachedLocset = 0;
1753 cache->dbgCachedUsers = 0;
1754 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001755 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001756
1757 cache->dbgReusedAll = 0;
1758 cache->dbgReusedNodeset = 0;
1759 cache->dbgReusedString = 0;
1760 cache->dbgReusedBool = 0;
1761 cache->dbgReusedNumber = 0;
1762 cache->dbgReusedPoint = 0;
1763 cache->dbgReusedRange = 0;
1764 cache->dbgReusedLocset = 0;
1765 cache->dbgReusedUsers = 0;
1766 cache->dbgReusedXSLTTree = 0;
1767 cache->dbgReusedUndefined = 0;
1768 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001769 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001770
1771 xmlXPathDebugObjCounterUndefined = 0;
1772 xmlXPathDebugObjCounterNodeset = 0;
1773 xmlXPathDebugObjCounterBool = 0;
1774 xmlXPathDebugObjCounterNumber = 0;
1775 xmlXPathDebugObjCounterString = 0;
1776 xmlXPathDebugObjCounterPoint = 0;
1777 xmlXPathDebugObjCounterRange = 0;
1778 xmlXPathDebugObjCounterLocset = 0;
1779 xmlXPathDebugObjCounterUsers = 0;
1780 xmlXPathDebugObjCounterXSLTTree = 0;
1781 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001782
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001783 xmlXPathDebugObjTotalUndefined = 0;
1784 xmlXPathDebugObjTotalNodeset = 0;
1785 xmlXPathDebugObjTotalBool = 0;
1786 xmlXPathDebugObjTotalNumber = 0;
1787 xmlXPathDebugObjTotalString = 0;
1788 xmlXPathDebugObjTotalPoint = 0;
1789 xmlXPathDebugObjTotalRange = 0;
1790 xmlXPathDebugObjTotalLocset = 0;
1791 xmlXPathDebugObjTotalUsers = 0;
1792 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001793 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001794
1795 xmlXPathDebugObjMaxUndefined = 0;
1796 xmlXPathDebugObjMaxNodeset = 0;
1797 xmlXPathDebugObjMaxBool = 0;
1798 xmlXPathDebugObjMaxNumber = 0;
1799 xmlXPathDebugObjMaxString = 0;
1800 xmlXPathDebugObjMaxPoint = 0;
1801 xmlXPathDebugObjMaxRange = 0;
1802 xmlXPathDebugObjMaxLocset = 0;
1803 xmlXPathDebugObjMaxUsers = 0;
1804 xmlXPathDebugObjMaxXSLTTree = 0;
1805 xmlXPathDebugObjMaxAll = 0;
1806
1807}
1808
1809static void
1810xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1811 xmlXPathObjectType objType)
1812{
1813 int isCached = 0;
1814
1815 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001816 if (ctxt->cache != NULL) {
1817 xmlXPathContextCachePtr cache =
1818 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001819
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001820 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001821
1822 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001823 switch (objType) {
1824 case XPATH_UNDEFINED:
1825 cache->dbgReusedUndefined++;
1826 break;
1827 case XPATH_NODESET:
1828 cache->dbgReusedNodeset++;
1829 break;
1830 case XPATH_BOOLEAN:
1831 cache->dbgReusedBool++;
1832 break;
1833 case XPATH_NUMBER:
1834 cache->dbgReusedNumber++;
1835 break;
1836 case XPATH_STRING:
1837 cache->dbgReusedString++;
1838 break;
1839 case XPATH_POINT:
1840 cache->dbgReusedPoint++;
1841 break;
1842 case XPATH_RANGE:
1843 cache->dbgReusedRange++;
1844 break;
1845 case XPATH_LOCATIONSET:
1846 cache->dbgReusedLocset++;
1847 break;
1848 case XPATH_USERS:
1849 cache->dbgReusedUsers++;
1850 break;
1851 case XPATH_XSLT_TREE:
1852 cache->dbgReusedXSLTTree++;
1853 break;
1854 default:
1855 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001856 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001857 }
1858 }
1859
1860 switch (objType) {
1861 case XPATH_UNDEFINED:
1862 if (! isCached)
1863 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001864 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001865 if (xmlXPathDebugObjCounterUndefined >
1866 xmlXPathDebugObjMaxUndefined)
1867 xmlXPathDebugObjMaxUndefined =
1868 xmlXPathDebugObjCounterUndefined;
1869 break;
1870 case XPATH_NODESET:
1871 if (! isCached)
1872 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001873 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001874 if (xmlXPathDebugObjCounterNodeset >
1875 xmlXPathDebugObjMaxNodeset)
1876 xmlXPathDebugObjMaxNodeset =
1877 xmlXPathDebugObjCounterNodeset;
1878 break;
1879 case XPATH_BOOLEAN:
1880 if (! isCached)
1881 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001882 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001883 if (xmlXPathDebugObjCounterBool >
1884 xmlXPathDebugObjMaxBool)
1885 xmlXPathDebugObjMaxBool =
1886 xmlXPathDebugObjCounterBool;
1887 break;
1888 case XPATH_NUMBER:
1889 if (! isCached)
1890 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001891 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001892 if (xmlXPathDebugObjCounterNumber >
1893 xmlXPathDebugObjMaxNumber)
1894 xmlXPathDebugObjMaxNumber =
1895 xmlXPathDebugObjCounterNumber;
1896 break;
1897 case XPATH_STRING:
1898 if (! isCached)
1899 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001900 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001901 if (xmlXPathDebugObjCounterString >
1902 xmlXPathDebugObjMaxString)
1903 xmlXPathDebugObjMaxString =
1904 xmlXPathDebugObjCounterString;
1905 break;
1906 case XPATH_POINT:
1907 if (! isCached)
1908 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001909 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001910 if (xmlXPathDebugObjCounterPoint >
1911 xmlXPathDebugObjMaxPoint)
1912 xmlXPathDebugObjMaxPoint =
1913 xmlXPathDebugObjCounterPoint;
1914 break;
1915 case XPATH_RANGE:
1916 if (! isCached)
1917 xmlXPathDebugObjTotalRange++;
1918 xmlXPathDebugObjCounterRange++;
1919 if (xmlXPathDebugObjCounterRange >
1920 xmlXPathDebugObjMaxRange)
1921 xmlXPathDebugObjMaxRange =
1922 xmlXPathDebugObjCounterRange;
1923 break;
1924 case XPATH_LOCATIONSET:
1925 if (! isCached)
1926 xmlXPathDebugObjTotalLocset++;
1927 xmlXPathDebugObjCounterLocset++;
1928 if (xmlXPathDebugObjCounterLocset >
1929 xmlXPathDebugObjMaxLocset)
1930 xmlXPathDebugObjMaxLocset =
1931 xmlXPathDebugObjCounterLocset;
1932 break;
1933 case XPATH_USERS:
1934 if (! isCached)
1935 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001936 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001937 if (xmlXPathDebugObjCounterUsers >
1938 xmlXPathDebugObjMaxUsers)
1939 xmlXPathDebugObjMaxUsers =
1940 xmlXPathDebugObjCounterUsers;
1941 break;
1942 case XPATH_XSLT_TREE:
1943 if (! isCached)
1944 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001945 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001946 if (xmlXPathDebugObjCounterXSLTTree >
1947 xmlXPathDebugObjMaxXSLTTree)
1948 xmlXPathDebugObjMaxXSLTTree =
1949 xmlXPathDebugObjCounterXSLTTree;
1950 break;
1951 default:
1952 break;
1953 }
1954 if (! isCached)
1955 xmlXPathDebugObjTotalAll++;
1956 xmlXPathDebugObjCounterAll++;
1957 if (xmlXPathDebugObjCounterAll >
1958 xmlXPathDebugObjMaxAll)
1959 xmlXPathDebugObjMaxAll =
1960 xmlXPathDebugObjCounterAll;
1961}
1962
1963static void
1964xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1965 xmlXPathObjectType objType)
1966{
1967 int isCached = 0;
1968
1969 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001970 if (ctxt->cache != NULL) {
1971 xmlXPathContextCachePtr cache =
1972 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001973
Daniel Veillard45490ae2008-07-29 09:13:19 +00001974 isCached = 1;
1975
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001976 cache->dbgCachedAll++;
1977 switch (objType) {
1978 case XPATH_UNDEFINED:
1979 cache->dbgCachedUndefined++;
1980 break;
1981 case XPATH_NODESET:
1982 cache->dbgCachedNodeset++;
1983 break;
1984 case XPATH_BOOLEAN:
1985 cache->dbgCachedBool++;
1986 break;
1987 case XPATH_NUMBER:
1988 cache->dbgCachedNumber++;
1989 break;
1990 case XPATH_STRING:
1991 cache->dbgCachedString++;
1992 break;
1993 case XPATH_POINT:
1994 cache->dbgCachedPoint++;
1995 break;
1996 case XPATH_RANGE:
1997 cache->dbgCachedRange++;
1998 break;
1999 case XPATH_LOCATIONSET:
2000 cache->dbgCachedLocset++;
2001 break;
2002 case XPATH_USERS:
2003 cache->dbgCachedUsers++;
2004 break;
2005 case XPATH_XSLT_TREE:
2006 cache->dbgCachedXSLTTree++;
2007 break;
2008 default:
2009 break;
2010 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002011
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002012 }
2013 }
2014 switch (objType) {
2015 case XPATH_UNDEFINED:
2016 xmlXPathDebugObjCounterUndefined--;
2017 break;
2018 case XPATH_NODESET:
2019 xmlXPathDebugObjCounterNodeset--;
2020 break;
2021 case XPATH_BOOLEAN:
2022 xmlXPathDebugObjCounterBool--;
2023 break;
2024 case XPATH_NUMBER:
2025 xmlXPathDebugObjCounterNumber--;
2026 break;
2027 case XPATH_STRING:
2028 xmlXPathDebugObjCounterString--;
2029 break;
2030 case XPATH_POINT:
2031 xmlXPathDebugObjCounterPoint--;
2032 break;
2033 case XPATH_RANGE:
2034 xmlXPathDebugObjCounterRange--;
2035 break;
2036 case XPATH_LOCATIONSET:
2037 xmlXPathDebugObjCounterLocset--;
2038 break;
2039 case XPATH_USERS:
2040 xmlXPathDebugObjCounterUsers--;
2041 break;
2042 case XPATH_XSLT_TREE:
2043 xmlXPathDebugObjCounterXSLTTree--;
2044 break;
2045 default:
2046 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002047 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002048 xmlXPathDebugObjCounterAll--;
2049}
2050
2051/* REVISIT TODO: Make this static when committing */
2052static void
2053xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2054{
2055 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2056 reqXSLTTree, reqUndefined;
2057 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2058 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2059 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2060 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2061 int leftObjs = xmlXPathDebugObjCounterAll;
2062
2063 reqAll = xmlXPathDebugObjTotalAll;
2064 reqNodeset = xmlXPathDebugObjTotalNodeset;
2065 reqString = xmlXPathDebugObjTotalString;
2066 reqBool = xmlXPathDebugObjTotalBool;
2067 reqNumber = xmlXPathDebugObjTotalNumber;
2068 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2069 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002070
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002071 printf("# XPath object usage:\n");
2072
2073 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002074 if (ctxt->cache != NULL) {
2075 xmlXPathContextCachePtr cache =
2076 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002077
2078 reAll = cache->dbgReusedAll;
2079 reqAll += reAll;
2080 reNodeset = cache->dbgReusedNodeset;
2081 reqNodeset += reNodeset;
2082 reString = cache->dbgReusedString;
2083 reqString += reString;
2084 reBool = cache->dbgReusedBool;
2085 reqBool += reBool;
2086 reNumber = cache->dbgReusedNumber;
2087 reqNumber += reNumber;
2088 reXSLTTree = cache->dbgReusedXSLTTree;
2089 reqXSLTTree += reXSLTTree;
2090 reUndefined = cache->dbgReusedUndefined;
2091 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002092
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002093 caAll = cache->dbgCachedAll;
2094 caBool = cache->dbgCachedBool;
2095 caNodeset = cache->dbgCachedNodeset;
2096 caString = cache->dbgCachedString;
2097 caNumber = cache->dbgCachedNumber;
2098 caXSLTTree = cache->dbgCachedXSLTTree;
2099 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002100
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002101 if (cache->nodesetObjs)
2102 leftObjs -= cache->nodesetObjs->number;
2103 if (cache->stringObjs)
2104 leftObjs -= cache->stringObjs->number;
2105 if (cache->booleanObjs)
2106 leftObjs -= cache->booleanObjs->number;
2107 if (cache->numberObjs)
2108 leftObjs -= cache->numberObjs->number;
2109 if (cache->miscObjs)
2110 leftObjs -= cache->miscObjs->number;
2111 }
2112 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002113
2114 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002115 printf("# total : %d\n", reqAll);
2116 printf("# left : %d\n", leftObjs);
2117 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2118 printf("# reused : %d\n", reAll);
2119 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2120
2121 printf("# node-sets\n");
2122 printf("# total : %d\n", reqNodeset);
2123 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2124 printf("# reused : %d\n", reNodeset);
2125 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2126
2127 printf("# strings\n");
2128 printf("# total : %d\n", reqString);
2129 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2130 printf("# reused : %d\n", reString);
2131 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2132
2133 printf("# booleans\n");
2134 printf("# total : %d\n", reqBool);
2135 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2136 printf("# reused : %d\n", reBool);
2137 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2138
2139 printf("# numbers\n");
2140 printf("# total : %d\n", reqNumber);
2141 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2142 printf("# reused : %d\n", reNumber);
2143 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2144
2145 printf("# XSLT result tree fragments\n");
2146 printf("# total : %d\n", reqXSLTTree);
2147 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2148 printf("# reused : %d\n", reXSLTTree);
2149 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2150
2151 printf("# undefined\n");
2152 printf("# total : %d\n", reqUndefined);
2153 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2154 printf("# reused : %d\n", reUndefined);
2155 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2156
2157}
2158
2159#endif /* XP_DEBUG_OBJ_USAGE */
2160
Daniel Veillard017b1082001-06-21 11:20:21 +00002161#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002162
2163/************************************************************************
2164 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002165 * XPath object caching *
2166 * *
2167 ************************************************************************/
2168
2169/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002170 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002171 *
2172 * Create a new object cache
2173 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002174 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002175 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002176static xmlXPathContextCachePtr
2177xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002178{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002179 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002180
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002181 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002182 if (ret == NULL) {
2183 xmlXPathErrMemory(NULL, "creating object cache\n");
2184 return(NULL);
2185 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002186 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002187 ret->maxNodeset = 100;
2188 ret->maxString = 100;
2189 ret->maxBoolean = 100;
2190 ret->maxNumber = 100;
2191 ret->maxMisc = 100;
2192 return(ret);
2193}
2194
2195static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002196xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002197{
2198 int i;
2199 xmlXPathObjectPtr obj;
2200
2201 if (list == NULL)
2202 return;
2203
2204 for (i = 0; i < list->number; i++) {
2205 obj = list->items[i];
2206 /*
2207 * Note that it is already assured that we don't need to
2208 * look out for namespace nodes in the node-set.
2209 */
2210 if (obj->nodesetval != NULL) {
2211 if (obj->nodesetval->nodeTab != NULL)
2212 xmlFree(obj->nodesetval->nodeTab);
2213 xmlFree(obj->nodesetval);
2214 }
2215 xmlFree(obj);
2216#ifdef XP_DEBUG_OBJ_USAGE
2217 xmlXPathDebugObjCounterAll--;
2218#endif
2219 }
2220 xmlPointerListFree(list);
2221}
2222
2223static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002224xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002225{
2226 if (cache == NULL)
2227 return;
2228 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002229 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002230 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002231 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002232 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002233 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002234 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002235 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002236 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002237 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002238 xmlFree(cache);
2239}
2240
2241/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002242 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002243 *
2244 * @ctxt: the XPath context
2245 * @active: enables/disables (creates/frees) the cache
Daniel Veillard45490ae2008-07-29 09:13:19 +00002246 * @value: a value with semantics dependant on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002247 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002248 *
2249 * Creates/frees an object cache on the XPath context.
2250 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002251 * to be reused.
2252 * @options:
2253 * 0: This will set the XPath object caching:
2254 * @value:
2255 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002256 * to be cached per slot
2257 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002258 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002259 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002260 *
2261 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2262 */
2263int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002264xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2265 int active,
2266 int value,
2267 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002268{
2269 if (ctxt == NULL)
2270 return(-1);
2271 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002272 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002273
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002274 if (ctxt->cache == NULL) {
2275 ctxt->cache = xmlXPathNewCache();
2276 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002277 return(-1);
2278 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002279 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002280 if (options == 0) {
2281 if (value < 0)
2282 value = 100;
2283 cache->maxNodeset = value;
2284 cache->maxString = value;
2285 cache->maxNumber = value;
2286 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002287 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002288 }
2289 } else if (ctxt->cache != NULL) {
2290 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2291 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002292 }
2293 return(0);
2294}
2295
2296/**
2297 * xmlXPathCacheWrapNodeSet:
2298 * @ctxt: the XPath context
2299 * @val: the NodePtr value
2300 *
2301 * This is the cached version of xmlXPathWrapNodeSet().
2302 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2303 *
2304 * Returns the created or reused object.
2305 */
2306static xmlXPathObjectPtr
2307xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002308{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002309 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2310 xmlXPathContextCachePtr cache =
2311 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002312
2313 if ((cache->miscObjs != NULL) &&
2314 (cache->miscObjs->number != 0))
2315 {
2316 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002317
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002318 ret = (xmlXPathObjectPtr)
2319 cache->miscObjs->items[--cache->miscObjs->number];
2320 ret->type = XPATH_NODESET;
2321 ret->nodesetval = val;
2322#ifdef XP_DEBUG_OBJ_USAGE
2323 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2324#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00002325 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002326 }
2327 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002328
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002329 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00002330
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002331}
2332
2333/**
2334 * xmlXPathCacheWrapString:
2335 * @ctxt: the XPath context
2336 * @val: the xmlChar * value
2337 *
2338 * This is the cached version of xmlXPathWrapString().
2339 * Wraps the @val string into an XPath object.
2340 *
2341 * Returns the created or reused object.
2342 */
2343static xmlXPathObjectPtr
2344xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002345{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002346 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2347 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002348
2349 if ((cache->stringObjs != NULL) &&
2350 (cache->stringObjs->number != 0))
2351 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002352
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002353 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002354
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002355 ret = (xmlXPathObjectPtr)
2356 cache->stringObjs->items[--cache->stringObjs->number];
2357 ret->type = XPATH_STRING;
2358 ret->stringval = val;
2359#ifdef XP_DEBUG_OBJ_USAGE
2360 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2361#endif
2362 return(ret);
2363 } else if ((cache->miscObjs != NULL) &&
2364 (cache->miscObjs->number != 0))
2365 {
2366 xmlXPathObjectPtr ret;
2367 /*
2368 * Fallback to misc-cache.
2369 */
2370 ret = (xmlXPathObjectPtr)
2371 cache->miscObjs->items[--cache->miscObjs->number];
2372
2373 ret->type = XPATH_STRING;
2374 ret->stringval = val;
2375#ifdef XP_DEBUG_OBJ_USAGE
2376 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2377#endif
2378 return(ret);
2379 }
2380 }
2381 return(xmlXPathWrapString(val));
2382}
2383
2384/**
2385 * xmlXPathCacheNewNodeSet:
2386 * @ctxt: the XPath context
2387 * @val: the NodePtr value
2388 *
2389 * This is the cached version of xmlXPathNewNodeSet().
2390 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2391 * it with the single Node @val
2392 *
2393 * Returns the created or reused object.
2394 */
2395static xmlXPathObjectPtr
2396xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2397{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002398 if ((ctxt != NULL) && (ctxt->cache)) {
2399 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002400
2401 if ((cache->nodesetObjs != NULL) &&
2402 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002403 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002404 xmlXPathObjectPtr ret;
2405 /*
2406 * Use the nodset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002407 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002408 ret = (xmlXPathObjectPtr)
2409 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2410 ret->type = XPATH_NODESET;
2411 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002412 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002413 if ((ret->nodesetval->nodeMax == 0) ||
2414 (val->type == XML_NAMESPACE_DECL))
2415 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002416 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002417 } else {
2418 ret->nodesetval->nodeTab[0] = val;
2419 ret->nodesetval->nodeNr = 1;
2420 }
2421 }
2422#ifdef XP_DEBUG_OBJ_USAGE
2423 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2424#endif
2425 return(ret);
2426 } else if ((cache->miscObjs != NULL) &&
2427 (cache->miscObjs->number != 0))
2428 {
2429 xmlXPathObjectPtr ret;
2430 /*
2431 * Fallback to misc-cache.
2432 */
2433
2434 ret = (xmlXPathObjectPtr)
2435 cache->miscObjs->items[--cache->miscObjs->number];
2436
2437 ret->type = XPATH_NODESET;
2438 ret->boolval = 0;
2439 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08002440 if (ret->nodesetval == NULL) {
2441 ctxt->lastError.domain = XML_FROM_XPATH;
2442 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2443 return(NULL);
2444 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002445#ifdef XP_DEBUG_OBJ_USAGE
2446 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2447#endif
2448 return(ret);
2449 }
2450 }
2451 return(xmlXPathNewNodeSet(val));
2452}
2453
2454/**
2455 * xmlXPathCacheNewCString:
2456 * @ctxt: the XPath context
2457 * @val: the char * value
2458 *
2459 * This is the cached version of xmlXPathNewCString().
2460 * Acquire an xmlXPathObjectPtr of type string and of value @val
2461 *
2462 * Returns the created or reused object.
2463 */
2464static xmlXPathObjectPtr
2465xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002466{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002467 if ((ctxt != NULL) && (ctxt->cache)) {
2468 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002469
2470 if ((cache->stringObjs != NULL) &&
2471 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002472 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002473 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002474
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002475 ret = (xmlXPathObjectPtr)
2476 cache->stringObjs->items[--cache->stringObjs->number];
2477
2478 ret->type = XPATH_STRING;
2479 ret->stringval = xmlStrdup(BAD_CAST val);
2480#ifdef XP_DEBUG_OBJ_USAGE
2481 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2482#endif
2483 return(ret);
2484 } else if ((cache->miscObjs != NULL) &&
2485 (cache->miscObjs->number != 0))
2486 {
2487 xmlXPathObjectPtr ret;
2488
2489 ret = (xmlXPathObjectPtr)
2490 cache->miscObjs->items[--cache->miscObjs->number];
2491
2492 ret->type = XPATH_STRING;
2493 ret->stringval = xmlStrdup(BAD_CAST val);
2494#ifdef XP_DEBUG_OBJ_USAGE
2495 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2496#endif
2497 return(ret);
2498 }
2499 }
2500 return(xmlXPathNewCString(val));
2501}
2502
2503/**
2504 * xmlXPathCacheNewString:
2505 * @ctxt: the XPath context
2506 * @val: the xmlChar * value
2507 *
2508 * This is the cached version of xmlXPathNewString().
2509 * Acquire an xmlXPathObjectPtr of type string and of value @val
2510 *
2511 * Returns the created or reused object.
2512 */
2513static xmlXPathObjectPtr
2514xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002515{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002516 if ((ctxt != NULL) && (ctxt->cache)) {
2517 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002518
2519 if ((cache->stringObjs != NULL) &&
2520 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002521 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002522 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002523
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002524 ret = (xmlXPathObjectPtr)
2525 cache->stringObjs->items[--cache->stringObjs->number];
2526 ret->type = XPATH_STRING;
2527 if (val != NULL)
2528 ret->stringval = xmlStrdup(val);
2529 else
2530 ret->stringval = xmlStrdup((const xmlChar *)"");
2531#ifdef XP_DEBUG_OBJ_USAGE
2532 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533#endif
2534 return(ret);
2535 } else if ((cache->miscObjs != NULL) &&
2536 (cache->miscObjs->number != 0))
2537 {
2538 xmlXPathObjectPtr ret;
2539
2540 ret = (xmlXPathObjectPtr)
2541 cache->miscObjs->items[--cache->miscObjs->number];
2542
2543 ret->type = XPATH_STRING;
2544 if (val != NULL)
2545 ret->stringval = xmlStrdup(val);
2546 else
2547 ret->stringval = xmlStrdup((const xmlChar *)"");
2548#ifdef XP_DEBUG_OBJ_USAGE
2549 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2550#endif
2551 return(ret);
2552 }
2553 }
2554 return(xmlXPathNewString(val));
2555}
2556
2557/**
2558 * xmlXPathCacheNewBoolean:
2559 * @ctxt: the XPath context
2560 * @val: the boolean value
2561 *
2562 * This is the cached version of xmlXPathNewBoolean().
2563 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2564 *
2565 * Returns the created or reused object.
2566 */
2567static xmlXPathObjectPtr
2568xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002569{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002570 if ((ctxt != NULL) && (ctxt->cache)) {
2571 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002572
2573 if ((cache->booleanObjs != NULL) &&
2574 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002575 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002576 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002577
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002578 ret = (xmlXPathObjectPtr)
2579 cache->booleanObjs->items[--cache->booleanObjs->number];
2580 ret->type = XPATH_BOOLEAN;
2581 ret->boolval = (val != 0);
2582#ifdef XP_DEBUG_OBJ_USAGE
2583 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2584#endif
2585 return(ret);
2586 } else if ((cache->miscObjs != NULL) &&
2587 (cache->miscObjs->number != 0))
2588 {
2589 xmlXPathObjectPtr ret;
2590
2591 ret = (xmlXPathObjectPtr)
2592 cache->miscObjs->items[--cache->miscObjs->number];
2593
2594 ret->type = XPATH_BOOLEAN;
2595 ret->boolval = (val != 0);
2596#ifdef XP_DEBUG_OBJ_USAGE
2597 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2598#endif
2599 return(ret);
2600 }
2601 }
2602 return(xmlXPathNewBoolean(val));
2603}
2604
2605/**
2606 * xmlXPathCacheNewFloat:
2607 * @ctxt: the XPath context
2608 * @val: the double value
2609 *
2610 * This is the cached version of xmlXPathNewFloat().
2611 * Acquires an xmlXPathObjectPtr of type double and of value @val
2612 *
2613 * Returns the created or reused object.
2614 */
2615static xmlXPathObjectPtr
2616xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2617{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002618 if ((ctxt != NULL) && (ctxt->cache)) {
2619 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002620
2621 if ((cache->numberObjs != NULL) &&
2622 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002623 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002624 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002625
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002626 ret = (xmlXPathObjectPtr)
2627 cache->numberObjs->items[--cache->numberObjs->number];
2628 ret->type = XPATH_NUMBER;
2629 ret->floatval = val;
2630#ifdef XP_DEBUG_OBJ_USAGE
2631 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2632#endif
2633 return(ret);
2634 } else if ((cache->miscObjs != NULL) &&
2635 (cache->miscObjs->number != 0))
2636 {
2637 xmlXPathObjectPtr ret;
2638
2639 ret = (xmlXPathObjectPtr)
2640 cache->miscObjs->items[--cache->miscObjs->number];
2641
2642 ret->type = XPATH_NUMBER;
2643 ret->floatval = val;
2644#ifdef XP_DEBUG_OBJ_USAGE
2645 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2646#endif
2647 return(ret);
2648 }
2649 }
2650 return(xmlXPathNewFloat(val));
2651}
2652
2653/**
2654 * xmlXPathCacheConvertString:
2655 * @ctxt: the XPath context
2656 * @val: an XPath object
2657 *
2658 * This is the cached version of xmlXPathConvertString().
2659 * Converts an existing object to its string() equivalent
2660 *
2661 * Returns a created or reused object, the old one is freed (cached)
2662 * (or the operation is done directly on @val)
2663 */
2664
2665static xmlXPathObjectPtr
2666xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002667 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002668
2669 if (val == NULL)
2670 return(xmlXPathCacheNewCString(ctxt, ""));
2671
2672 switch (val->type) {
2673 case XPATH_UNDEFINED:
2674#ifdef DEBUG_EXPR
2675 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2676#endif
2677 break;
2678 case XPATH_NODESET:
2679 case XPATH_XSLT_TREE:
2680 res = xmlXPathCastNodeSetToString(val->nodesetval);
2681 break;
2682 case XPATH_STRING:
2683 return(val);
2684 case XPATH_BOOLEAN:
2685 res = xmlXPathCastBooleanToString(val->boolval);
2686 break;
2687 case XPATH_NUMBER:
2688 res = xmlXPathCastNumberToString(val->floatval);
2689 break;
2690 case XPATH_USERS:
2691 case XPATH_POINT:
2692 case XPATH_RANGE:
2693 case XPATH_LOCATIONSET:
2694 TODO;
2695 break;
2696 }
2697 xmlXPathReleaseObject(ctxt, val);
2698 if (res == NULL)
2699 return(xmlXPathCacheNewCString(ctxt, ""));
2700 return(xmlXPathCacheWrapString(ctxt, res));
2701}
2702
2703/**
2704 * xmlXPathCacheObjectCopy:
2705 * @ctxt: the XPath context
2706 * @val: the original object
2707 *
2708 * This is the cached version of xmlXPathObjectCopy().
2709 * Acquire a copy of a given object
2710 *
2711 * Returns a created or reused created object.
2712 */
2713static xmlXPathObjectPtr
2714xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2715{
2716 if (val == NULL)
2717 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002718
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002719 if (XP_HAS_CACHE(ctxt)) {
2720 switch (val->type) {
2721 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002722 return(xmlXPathCacheWrapNodeSet(ctxt,
2723 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002724 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002725 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002726 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002727 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002728 case XPATH_NUMBER:
2729 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2730 default:
2731 break;
2732 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002733 }
2734 return(xmlXPathObjectCopy(val));
2735}
2736
2737/**
2738 * xmlXPathCacheConvertBoolean:
2739 * @ctxt: the XPath context
2740 * @val: an XPath object
2741 *
2742 * This is the cached version of xmlXPathConvertBoolean().
2743 * Converts an existing object to its boolean() equivalent
2744 *
2745 * Returns a created or reused object, the old one is freed (or the operation
2746 * is done directly on @val)
2747 */
2748static xmlXPathObjectPtr
2749xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2750 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002751
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002752 if (val == NULL)
2753 return(xmlXPathCacheNewBoolean(ctxt, 0));
2754 if (val->type == XPATH_BOOLEAN)
2755 return(val);
2756 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2757 xmlXPathReleaseObject(ctxt, val);
2758 return(ret);
2759}
2760
2761/**
2762 * xmlXPathCacheConvertNumber:
2763 * @ctxt: the XPath context
2764 * @val: an XPath object
2765 *
2766 * This is the cached version of xmlXPathConvertNumber().
2767 * Converts an existing object to its number() equivalent
2768 *
2769 * Returns a created or reused object, the old one is freed (or the operation
2770 * is done directly on @val)
2771 */
2772static xmlXPathObjectPtr
2773xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002775
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002776 if (val == NULL)
2777 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2778 if (val->type == XPATH_NUMBER)
2779 return(val);
2780 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2781 xmlXPathReleaseObject(ctxt, val);
2782 return(ret);
2783}
2784
2785/************************************************************************
2786 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002787 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002788 * *
2789 ************************************************************************/
2790
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002791/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002792 * xmlXPathSetFrame:
2793 * @ctxt: an XPath parser context
2794 *
2795 * Set the callee evaluation frame
2796 *
2797 * Returns the previous frame value to be restored once done
2798 */
2799static int
2800xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2801 int ret;
2802
2803 if (ctxt == NULL)
2804 return(0);
2805 ret = ctxt->valueFrame;
2806 ctxt->valueFrame = ctxt->valueNr;
2807 return(ret);
2808}
2809
2810/**
2811 * xmlXPathPopFrame:
2812 * @ctxt: an XPath parser context
2813 * @frame: the previous frame value
2814 *
2815 * Remove the callee evaluation frame
2816 */
2817static void
2818xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2819 if (ctxt == NULL)
2820 return;
2821 if (ctxt->valueNr < ctxt->valueFrame) {
2822 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2823 }
2824 ctxt->valueFrame = frame;
2825}
2826
2827/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002828 * valuePop:
2829 * @ctxt: an XPath evaluation context
2830 *
2831 * Pops the top XPath object from the value stack
2832 *
2833 * Returns the XPath object just removed
2834 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002835xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002836valuePop(xmlXPathParserContextPtr ctxt)
2837{
2838 xmlXPathObjectPtr ret;
2839
Daniel Veillarda82b1822004-11-08 16:24:57 +00002840 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002841 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002842
2843 if (ctxt->valueNr <= ctxt->valueFrame) {
2844 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2845 return (NULL);
2846 }
2847
Daniel Veillard1c732d22002-11-30 11:22:59 +00002848 ctxt->valueNr--;
2849 if (ctxt->valueNr > 0)
2850 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2851 else
2852 ctxt->value = NULL;
2853 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002854 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002855 return (ret);
2856}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002857/**
2858 * valuePush:
2859 * @ctxt: an XPath evaluation context
2860 * @value: the XPath object
2861 *
2862 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002863 *
2864 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002865 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002866int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002867valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2868{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002869 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002870 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002871 xmlXPathObjectPtr *tmp;
2872
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002873 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2874 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2875 ctxt->error = XPATH_MEMORY_ERROR;
2876 return (0);
2877 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002878 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2879 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002880 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002881 if (tmp == NULL) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002882 xmlXPathErrMemory(NULL, "pushing value\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08002883 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002884 return (0);
2885 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002886 ctxt->valueMax *= 2;
2887 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002888 }
2889 ctxt->valueTab[ctxt->valueNr] = value;
2890 ctxt->value = value;
2891 return (ctxt->valueNr++);
2892}
Owen Taylor3473f882001-02-23 17:55:21 +00002893
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002894/**
2895 * xmlXPathPopBoolean:
2896 * @ctxt: an XPath parser context
2897 *
2898 * Pops a boolean from the stack, handling conversion if needed.
2899 * Check error with #xmlXPathCheckError.
2900 *
2901 * Returns the boolean
2902 */
2903int
2904xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2905 xmlXPathObjectPtr obj;
2906 int ret;
2907
2908 obj = valuePop(ctxt);
2909 if (obj == NULL) {
2910 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2911 return(0);
2912 }
William M. Brack08171912003-12-29 02:52:11 +00002913 if (obj->type != XPATH_BOOLEAN)
2914 ret = xmlXPathCastToBoolean(obj);
2915 else
2916 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002917 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002918 return(ret);
2919}
2920
2921/**
2922 * xmlXPathPopNumber:
2923 * @ctxt: an XPath parser context
2924 *
2925 * Pops a number from the stack, handling conversion if needed.
2926 * Check error with #xmlXPathCheckError.
2927 *
2928 * Returns the number
2929 */
2930double
2931xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2932 xmlXPathObjectPtr obj;
2933 double ret;
2934
2935 obj = valuePop(ctxt);
2936 if (obj == NULL) {
2937 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2938 return(0);
2939 }
William M. Brack08171912003-12-29 02:52:11 +00002940 if (obj->type != XPATH_NUMBER)
2941 ret = xmlXPathCastToNumber(obj);
2942 else
2943 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002944 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002945 return(ret);
2946}
2947
2948/**
2949 * xmlXPathPopString:
2950 * @ctxt: an XPath parser context
2951 *
2952 * Pops a string from the stack, handling conversion if needed.
2953 * Check error with #xmlXPathCheckError.
2954 *
2955 * Returns the string
2956 */
2957xmlChar *
2958xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2959 xmlXPathObjectPtr obj;
2960 xmlChar * ret;
2961
2962 obj = valuePop(ctxt);
2963 if (obj == NULL) {
2964 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2965 return(NULL);
2966 }
William M. Brack08171912003-12-29 02:52:11 +00002967 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002968 /* TODO: needs refactoring somewhere else */
2969 if (obj->stringval == ret)
2970 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002971 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002972 return(ret);
2973}
2974
2975/**
2976 * xmlXPathPopNodeSet:
2977 * @ctxt: an XPath parser context
2978 *
2979 * Pops a node-set from the stack, handling conversion if needed.
2980 * Check error with #xmlXPathCheckError.
2981 *
2982 * Returns the node-set
2983 */
2984xmlNodeSetPtr
2985xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2986 xmlXPathObjectPtr obj;
2987 xmlNodeSetPtr ret;
2988
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002989 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002990 if (ctxt->value == NULL) {
2991 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2992 return(NULL);
2993 }
2994 if (!xmlXPathStackIsNodeSet(ctxt)) {
2995 xmlXPathSetTypeError(ctxt);
2996 return(NULL);
2997 }
2998 obj = valuePop(ctxt);
2999 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00003000#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00003001 /* to fix memory leak of not clearing obj->user */
3002 if (obj->boolval && obj->user != NULL)
3003 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003004#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003005 obj->nodesetval = NULL;
3006 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003007 return(ret);
3008}
3009
3010/**
3011 * xmlXPathPopExternal:
3012 * @ctxt: an XPath parser context
3013 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003014 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003015 * Check error with #xmlXPathCheckError.
3016 *
3017 * Returns the object
3018 */
3019void *
3020xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3021 xmlXPathObjectPtr obj;
3022 void * ret;
3023
Daniel Veillarda82b1822004-11-08 16:24:57 +00003024 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003025 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3026 return(NULL);
3027 }
3028 if (ctxt->value->type != XPATH_USERS) {
3029 xmlXPathSetTypeError(ctxt);
3030 return(NULL);
3031 }
3032 obj = valuePop(ctxt);
3033 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003034 obj->user = NULL;
3035 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003036 return(ret);
3037}
3038
Owen Taylor3473f882001-02-23 17:55:21 +00003039/*
3040 * Macros for accessing the content. Those should be used only by the parser,
3041 * and not exported.
3042 *
3043 * Dirty macros, i.e. one need to make assumption on the context to use them
3044 *
3045 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3046 * CUR returns the current xmlChar value, i.e. a 8 bit value
3047 * in ISO-Latin or UTF-8.
3048 * This should be used internally by the parser
3049 * only to compare to ASCII values otherwise it would break when
3050 * running with UTF-8 encoding.
3051 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3052 * to compare on ASCII based substring.
3053 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3054 * strings within the parser.
3055 * CURRENT Returns the current char value, with the full decoding of
3056 * UTF-8 if we are using this mode. It returns an int.
3057 * NEXT Skip to the next character, this does the proper decoding
3058 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3059 * It returns the pointer to the current xmlChar.
3060 */
3061
3062#define CUR (*ctxt->cur)
3063#define SKIP(val) ctxt->cur += (val)
3064#define NXT(val) ctxt->cur[(val)]
3065#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00003066#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3067
3068#define COPY_BUF(l,b,i,v) \
3069 if (l == 1) b[i++] = (xmlChar) v; \
3070 else i += xmlCopyChar(l,&b[i],v)
3071
3072#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00003073
Daniel Veillard45490ae2008-07-29 09:13:19 +00003074#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00003075 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00003076
3077#define CURRENT (*ctxt->cur)
3078#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3079
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003080
3081#ifndef DBL_DIG
3082#define DBL_DIG 16
3083#endif
3084#ifndef DBL_EPSILON
3085#define DBL_EPSILON 1E-9
3086#endif
3087
3088#define UPPER_DOUBLE 1E9
3089#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00003090#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003091
3092#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00003093#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003094#define EXPONENT_DIGITS (3 + 2)
3095
3096/**
3097 * xmlXPathFormatNumber:
3098 * @number: number to format
3099 * @buffer: output buffer
3100 * @buffersize: size of output buffer
3101 *
3102 * Convert the number into a string representation.
3103 */
3104static void
3105xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3106{
Daniel Veillardcda96922001-08-21 10:56:31 +00003107 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003108 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003109 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003110 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003111 break;
3112 case -1:
3113 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003114 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003115 break;
3116 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003117 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003118 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003119 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003120 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003121 snprintf(buffer, buffersize, "0");
Nick Wellnhofer7482f412017-06-01 22:00:19 +02003122 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3123 (number == (int) number)) {
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003124 char work[30];
3125 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00003126 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003127
3128 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003129 if (value == 0) {
3130 *ptr++ = '0';
3131 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00003132 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003133 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00003134 while ((*cur) && (ptr - buffer < buffersize)) {
3135 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003136 }
3137 }
3138 if (ptr - buffer < buffersize) {
3139 *ptr = 0;
3140 } else if (buffersize > 0) {
3141 ptr--;
3142 *ptr = 0;
3143 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003144 } else {
William M. Brackca797882007-05-11 14:45:53 +00003145 /*
3146 For the dimension of work,
3147 DBL_DIG is number of significant digits
3148 EXPONENT is only needed for "scientific notation"
3149 3 is sign, decimal point, and terminating zero
3150 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3151 Note that this dimension is slightly (a few characters)
3152 larger than actually necessary.
3153 */
3154 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003155 int integer_place, fraction_place;
3156 char *ptr;
3157 char *after_fraction;
3158 double absolute_value;
3159 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003160
Bjorn Reese70a9da52001-04-21 16:57:29 +00003161 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003162
Bjorn Reese70a9da52001-04-21 16:57:29 +00003163 /*
3164 * First choose format - scientific or regular floating point.
3165 * In either case, result is in work, and after_fraction points
3166 * just past the fractional part.
3167 */
3168 if ( ((absolute_value > UPPER_DOUBLE) ||
3169 (absolute_value < LOWER_DOUBLE)) &&
3170 (absolute_value != 0.0) ) {
3171 /* Use scientific notation */
3172 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3173 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003174 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00003175 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00003176 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003177
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003178 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003179 else {
3180 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00003181 if (absolute_value > 0.0) {
3182 integer_place = (int)log10(absolute_value);
3183 if (integer_place > 0)
3184 fraction_place = DBL_DIG - integer_place - 1;
3185 else
3186 fraction_place = DBL_DIG - integer_place;
3187 } else {
3188 fraction_place = 1;
3189 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003190 size = snprintf(work, sizeof(work), "%0.*f",
3191 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003192 }
3193
Daniel Veillardb9e4d5b2013-07-22 13:21:31 +08003194 /* Remove leading spaces sometimes inserted by snprintf */
3195 while (work[0] == ' ') {
3196 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3197 size--;
3198 }
3199
Bjorn Reese70a9da52001-04-21 16:57:29 +00003200 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00003201 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003202 ptr = after_fraction;
3203 while (*(--ptr) == '0')
3204 ;
3205 if (*ptr != '.')
3206 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003207 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003208
3209 /* Finally copy result back to caller */
3210 size = strlen(work) + 1;
3211 if (size > buffersize) {
3212 work[buffersize - 1] = 0;
3213 size = buffersize;
3214 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003215 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003216 }
3217 break;
3218 }
3219}
3220
Owen Taylor3473f882001-02-23 17:55:21 +00003221
3222/************************************************************************
3223 * *
3224 * Routines to handle NodeSets *
3225 * *
3226 ************************************************************************/
3227
3228/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003229 * xmlXPathOrderDocElems:
3230 * @doc: an input document
3231 *
3232 * Call this routine to speed up XPath computation on static documents.
3233 * This stamps all the element nodes with the document order
3234 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00003235 * field, the value stored is actually - the node number (starting at -1)
3236 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003237 *
William M. Brack08171912003-12-29 02:52:11 +00003238 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003239 * of error.
3240 */
3241long
3242xmlXPathOrderDocElems(xmlDocPtr doc) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003243 ptrdiff_t count = 0;
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003244 xmlNodePtr cur;
3245
3246 if (doc == NULL)
3247 return(-1);
3248 cur = doc->children;
3249 while (cur != NULL) {
3250 if (cur->type == XML_ELEMENT_NODE) {
3251 cur->content = (void *) (-(++count));
3252 if (cur->children != NULL) {
3253 cur = cur->children;
3254 continue;
3255 }
3256 }
3257 if (cur->next != NULL) {
3258 cur = cur->next;
3259 continue;
3260 }
3261 do {
3262 cur = cur->parent;
3263 if (cur == NULL)
3264 break;
3265 if (cur == (xmlNodePtr) doc) {
3266 cur = NULL;
3267 break;
3268 }
3269 if (cur->next != NULL) {
3270 cur = cur->next;
3271 break;
3272 }
3273 } while (cur != NULL);
3274 }
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003275 return((long) count);
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003276}
3277
3278/**
Owen Taylor3473f882001-02-23 17:55:21 +00003279 * xmlXPathCmpNodes:
3280 * @node1: the first node
3281 * @node2: the second node
3282 *
3283 * Compare two nodes w.r.t document order
3284 *
3285 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00003286 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003287 */
3288int
3289xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3290 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003291 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003292 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003293 xmlNodePtr cur, root;
3294
3295 if ((node1 == NULL) || (node2 == NULL))
3296 return(-2);
3297 /*
3298 * a couple of optimizations which will avoid computations in most cases
3299 */
William M. Brackee0b9822007-03-07 08:15:01 +00003300 if (node1 == node2) /* trivial case */
3301 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00003302 if (node1->type == XML_ATTRIBUTE_NODE) {
3303 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003304 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003305 node1 = node1->parent;
3306 }
3307 if (node2->type == XML_ATTRIBUTE_NODE) {
3308 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003309 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003310 node2 = node2->parent;
3311 }
3312 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00003313 if (attr1 == attr2) {
3314 /* not required, but we keep attributes in order */
3315 if (attr1 != 0) {
3316 cur = attrNode2->prev;
3317 while (cur != NULL) {
3318 if (cur == attrNode1)
3319 return (1);
3320 cur = cur->prev;
3321 }
3322 return (-1);
3323 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003324 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00003325 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003326 if (attr2 == 1)
3327 return(1);
3328 return(-1);
3329 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003330 if ((node1->type == XML_NAMESPACE_DECL) ||
3331 (node2->type == XML_NAMESPACE_DECL))
3332 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003333 if (node1 == node2->prev)
3334 return(1);
3335 if (node1 == node2->next)
3336 return(-1);
3337
3338 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003339 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003340 */
3341 if ((node1->type == XML_ELEMENT_NODE) &&
3342 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003343 (0 > (ptrdiff_t) node1->content) &&
3344 (0 > (ptrdiff_t) node2->content) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003345 (node1->doc == node2->doc)) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003346 ptrdiff_t l1, l2;
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003347
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003348 l1 = -((ptrdiff_t) node1->content);
3349 l2 = -((ptrdiff_t) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003350 if (l1 < l2)
3351 return(1);
3352 if (l1 > l2)
3353 return(-1);
3354 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003355
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003356 /*
Owen Taylor3473f882001-02-23 17:55:21 +00003357 * compute depth to root
3358 */
3359 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003360 if (cur->parent == node1)
Owen Taylor3473f882001-02-23 17:55:21 +00003361 return(1);
3362 depth2++;
3363 }
3364 root = cur;
3365 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003366 if (cur->parent == node2)
Owen Taylor3473f882001-02-23 17:55:21 +00003367 return(-1);
3368 depth1++;
3369 }
3370 /*
3371 * Distinct document (or distinct entities :-( ) case.
3372 */
3373 if (root != cur) {
3374 return(-2);
3375 }
3376 /*
3377 * get the nearest common ancestor.
3378 */
3379 while (depth1 > depth2) {
3380 depth1--;
3381 node1 = node1->parent;
3382 }
3383 while (depth2 > depth1) {
3384 depth2--;
3385 node2 = node2->parent;
3386 }
3387 while (node1->parent != node2->parent) {
3388 node1 = node1->parent;
3389 node2 = node2->parent;
3390 /* should not happen but just in case ... */
3391 if ((node1 == NULL) || (node2 == NULL))
3392 return(-2);
3393 }
3394 /*
3395 * Find who's first.
3396 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003397 if (node1 == node2->prev)
3398 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003399 if (node1 == node2->next)
3400 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003401 /*
3402 * Speedup using document order if availble.
3403 */
3404 if ((node1->type == XML_ELEMENT_NODE) &&
3405 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003406 (0 > (ptrdiff_t) node1->content) &&
3407 (0 > (ptrdiff_t) node2->content) &&
Daniel Veillardf49be472004-02-17 11:48:18 +00003408 (node1->doc == node2->doc)) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003409 ptrdiff_t l1, l2;
Daniel Veillardf49be472004-02-17 11:48:18 +00003410
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003411 l1 = -((ptrdiff_t) node1->content);
3412 l2 = -((ptrdiff_t) node2->content);
Daniel Veillardf49be472004-02-17 11:48:18 +00003413 if (l1 < l2)
3414 return(1);
3415 if (l1 > l2)
3416 return(-1);
3417 }
3418
Owen Taylor3473f882001-02-23 17:55:21 +00003419 for (cur = node1->next;cur != NULL;cur = cur->next)
3420 if (cur == node2)
3421 return(1);
3422 return(-1); /* assume there is no sibling list corruption */
3423}
3424
3425/**
3426 * xmlXPathNodeSetSort:
3427 * @set: the node set
3428 *
3429 * Sort the node set in document order
3430 */
3431void
3432xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Vojtech Fried3e031b72012-08-24 16:52:44 +08003433#ifndef WITH_TIM_SORT
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003434 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003435 xmlNodePtr tmp;
Vojtech Fried3e031b72012-08-24 16:52:44 +08003436#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003437
3438 if (set == NULL)
3439 return;
3440
Vojtech Fried3e031b72012-08-24 16:52:44 +08003441#ifndef WITH_TIM_SORT
3442 /*
3443 * Use the old Shell's sort implementation to sort the node-set
3444 * Timsort ought to be quite faster
3445 */
Owen Taylor3473f882001-02-23 17:55:21 +00003446 len = set->nodeNr;
3447 for (incr = len / 2; incr > 0; incr /= 2) {
3448 for (i = incr; i < len; i++) {
3449 j = i - incr;
3450 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003451#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003452 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3453 set->nodeTab[j + incr]) == -1)
3454#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003455 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003456 set->nodeTab[j + incr]) == -1)
3457#endif
3458 {
Owen Taylor3473f882001-02-23 17:55:21 +00003459 tmp = set->nodeTab[j];
3460 set->nodeTab[j] = set->nodeTab[j + incr];
3461 set->nodeTab[j + incr] = tmp;
3462 j -= incr;
3463 } else
3464 break;
3465 }
3466 }
3467 }
Vojtech Fried3e031b72012-08-24 16:52:44 +08003468#else /* WITH_TIM_SORT */
3469 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3470#endif /* WITH_TIM_SORT */
Owen Taylor3473f882001-02-23 17:55:21 +00003471}
3472
3473#define XML_NODESET_DEFAULT 10
3474/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003475 * xmlXPathNodeSetDupNs:
3476 * @node: the parent node of the namespace XPath node
3477 * @ns: the libxml namespace declaration node.
3478 *
3479 * Namespace node in libxml don't match the XPath semantic. In a node set
3480 * the namespace nodes are duplicated and the next pointer is set to the
3481 * parent node in the XPath semantic.
3482 *
3483 * Returns the newly created object.
3484 */
3485static xmlNodePtr
3486xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3487 xmlNsPtr cur;
3488
3489 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3490 return(NULL);
3491 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3492 return((xmlNodePtr) ns);
3493
3494 /*
3495 * Allocate a new Namespace and fill the fields.
3496 */
3497 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3498 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003499 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003500 return(NULL);
3501 }
3502 memset(cur, 0, sizeof(xmlNs));
3503 cur->type = XML_NAMESPACE_DECL;
3504 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003505 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003506 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003507 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003508 cur->next = (xmlNsPtr) node;
3509 return((xmlNodePtr) cur);
3510}
3511
3512/**
3513 * xmlXPathNodeSetFreeNs:
3514 * @ns: the XPath namespace node found in a nodeset.
3515 *
William M. Brack08171912003-12-29 02:52:11 +00003516 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003517 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003518 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003519 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003520void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003521xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3522 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3523 return;
3524
3525 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3526 if (ns->href != NULL)
3527 xmlFree((xmlChar *)ns->href);
3528 if (ns->prefix != NULL)
3529 xmlFree((xmlChar *)ns->prefix);
3530 xmlFree(ns);
3531 }
3532}
3533
3534/**
Owen Taylor3473f882001-02-23 17:55:21 +00003535 * xmlXPathNodeSetCreate:
3536 * @val: an initial xmlNodePtr, or NULL
3537 *
3538 * Create a new xmlNodeSetPtr of type double and of value @val
3539 *
3540 * Returns the newly created object.
3541 */
3542xmlNodeSetPtr
3543xmlXPathNodeSetCreate(xmlNodePtr val) {
3544 xmlNodeSetPtr ret;
3545
3546 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3547 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003548 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003549 return(NULL);
3550 }
3551 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3552 if (val != NULL) {
3553 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3554 sizeof(xmlNodePtr));
3555 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003556 xmlXPathErrMemory(NULL, "creating nodeset\n");
3557 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003558 return(NULL);
3559 }
3560 memset(ret->nodeTab, 0 ,
3561 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3562 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003563 if (val->type == XML_NAMESPACE_DECL) {
3564 xmlNsPtr ns = (xmlNsPtr) val;
3565
3566 ret->nodeTab[ret->nodeNr++] =
3567 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3568 } else
3569 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003570 }
3571 return(ret);
3572}
3573
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003574/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003575 * xmlXPathNodeSetCreateSize:
3576 * @size: the initial size of the set
3577 *
3578 * Create a new xmlNodeSetPtr of type double and of value @val
3579 *
3580 * Returns the newly created object.
3581 */
3582static xmlNodeSetPtr
3583xmlXPathNodeSetCreateSize(int size) {
3584 xmlNodeSetPtr ret;
3585
3586 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3587 if (ret == NULL) {
3588 xmlXPathErrMemory(NULL, "creating nodeset\n");
3589 return(NULL);
3590 }
3591 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3592 if (size < XML_NODESET_DEFAULT)
3593 size = XML_NODESET_DEFAULT;
3594 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3595 if (ret->nodeTab == NULL) {
3596 xmlXPathErrMemory(NULL, "creating nodeset\n");
3597 xmlFree(ret);
3598 return(NULL);
3599 }
3600 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003601 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003602 return(ret);
3603}
3604
3605/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003606 * xmlXPathNodeSetContains:
3607 * @cur: the node-set
3608 * @val: the node
3609 *
3610 * checks whether @cur contains @val
3611 *
3612 * Returns true (1) if @cur contains @val, false (0) otherwise
3613 */
3614int
3615xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3616 int i;
3617
Daniel Veillarda82b1822004-11-08 16:24:57 +00003618 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003619 if (val->type == XML_NAMESPACE_DECL) {
3620 for (i = 0; i < cur->nodeNr; i++) {
3621 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3622 xmlNsPtr ns1, ns2;
3623
3624 ns1 = (xmlNsPtr) val;
3625 ns2 = (xmlNsPtr) cur->nodeTab[i];
3626 if (ns1 == ns2)
3627 return(1);
3628 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3629 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3630 return(1);
3631 }
3632 }
3633 } else {
3634 for (i = 0; i < cur->nodeNr; i++) {
3635 if (cur->nodeTab[i] == val)
3636 return(1);
3637 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003638 }
3639 return(0);
3640}
3641
3642/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003643 * xmlXPathNodeSetAddNs:
3644 * @cur: the initial node set
3645 * @node: the hosting node
3646 * @ns: a the namespace node
3647 *
3648 * add a new namespace node to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003649 *
3650 * Returns 0 in case of success and -1 in case of error
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003651 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003652int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003653xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3654 int i;
3655
Daniel Veillard45490ae2008-07-29 09:13:19 +00003656
Daniel Veillarda82b1822004-11-08 16:24:57 +00003657 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3658 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003659 (node->type != XML_ELEMENT_NODE))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003660 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003661
William M. Brack08171912003-12-29 02:52:11 +00003662 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003663 /*
William M. Brack08171912003-12-29 02:52:11 +00003664 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003665 */
3666 for (i = 0;i < cur->nodeNr;i++) {
3667 if ((cur->nodeTab[i] != NULL) &&
3668 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003669 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003670 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003671 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003672 }
3673
3674 /*
3675 * grow the nodeTab if needed
3676 */
3677 if (cur->nodeMax == 0) {
3678 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3679 sizeof(xmlNodePtr));
3680 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003681 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003682 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003683 }
3684 memset(cur->nodeTab, 0 ,
3685 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3686 cur->nodeMax = XML_NODESET_DEFAULT;
3687 } else if (cur->nodeNr == cur->nodeMax) {
3688 xmlNodePtr *temp;
3689
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003690 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3691 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003692 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003693 }
Chris Evansd7958b22011-03-23 08:13:06 +08003694 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003695 sizeof(xmlNodePtr));
3696 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003697 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003698 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003699 }
Chris Evansd7958b22011-03-23 08:13:06 +08003700 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003701 cur->nodeTab = temp;
3702 }
3703 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003704 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003705}
3706
3707/**
Owen Taylor3473f882001-02-23 17:55:21 +00003708 * xmlXPathNodeSetAdd:
3709 * @cur: the initial node set
3710 * @val: a new xmlNodePtr
3711 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003712 * add a new xmlNodePtr to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003713 *
3714 * Returns 0 in case of success, and -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00003715 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003716int
Owen Taylor3473f882001-02-23 17:55:21 +00003717xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3718 int i;
3719
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003720 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003721
William M. Brack08171912003-12-29 02:52:11 +00003722 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003723 /*
Shlomi Fishd5bd2a92016-04-03 05:14:44 +03003724 * prevent duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003725 */
3726 for (i = 0;i < cur->nodeNr;i++)
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003727 if (cur->nodeTab[i] == val) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003728
3729 /*
3730 * grow the nodeTab if needed
3731 */
3732 if (cur->nodeMax == 0) {
3733 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3734 sizeof(xmlNodePtr));
3735 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003736 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003737 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003738 }
3739 memset(cur->nodeTab, 0 ,
3740 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3741 cur->nodeMax = XML_NODESET_DEFAULT;
3742 } else if (cur->nodeNr == cur->nodeMax) {
3743 xmlNodePtr *temp;
3744
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003745 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3746 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003747 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003748 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003749 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003750 sizeof(xmlNodePtr));
3751 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003752 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003753 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003754 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003755 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003756 cur->nodeTab = temp;
3757 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003758 if (val->type == XML_NAMESPACE_DECL) {
3759 xmlNsPtr ns = (xmlNsPtr) val;
3760
Daniel Veillard45490ae2008-07-29 09:13:19 +00003761 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003762 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3763 } else
3764 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003765 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003766}
3767
3768/**
3769 * xmlXPathNodeSetAddUnique:
3770 * @cur: the initial node set
3771 * @val: a new xmlNodePtr
3772 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003773 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003774 * when we are sure the node is not already in the set.
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003775 *
3776 * Returns 0 in case of success and -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00003777 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003778int
Owen Taylor3473f882001-02-23 17:55:21 +00003779xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003780 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003781
William M. Brack08171912003-12-29 02:52:11 +00003782 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003783 /*
3784 * grow the nodeTab if needed
3785 */
3786 if (cur->nodeMax == 0) {
3787 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3788 sizeof(xmlNodePtr));
3789 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003790 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003791 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003792 }
3793 memset(cur->nodeTab, 0 ,
3794 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3795 cur->nodeMax = XML_NODESET_DEFAULT;
3796 } else if (cur->nodeNr == cur->nodeMax) {
3797 xmlNodePtr *temp;
3798
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003799 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3800 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003801 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003802 }
Chris Evansd7958b22011-03-23 08:13:06 +08003803 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003804 sizeof(xmlNodePtr));
3805 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003806 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003807 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003808 }
3809 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003810 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003811 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003812 if (val->type == XML_NAMESPACE_DECL) {
3813 xmlNsPtr ns = (xmlNsPtr) val;
3814
Daniel Veillard45490ae2008-07-29 09:13:19 +00003815 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003816 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3817 } else
3818 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003819 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003820}
3821
3822/**
3823 * xmlXPathNodeSetMerge:
3824 * @val1: the first NodeSet or NULL
3825 * @val2: the second NodeSet
3826 *
3827 * Merges two nodesets, all nodes from @val2 are added to @val1
3828 * if @val1 is NULL, a new set is created and copied from @val2
3829 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003830 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003831 */
3832xmlNodeSetPtr
3833xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003834 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003835 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003836
3837 if (val2 == NULL) return(val1);
3838 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003839 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003840 if (val1 == NULL)
3841 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003842#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003843 /*
3844 * TODO: The optimization won't work in every case, since
3845 * those nasty namespace nodes need to be added with
3846 * xmlXPathNodeSetDupNs() to the set; thus a pure
3847 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003848 * If there was a flag on the nodesetval, indicating that
3849 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003850 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003851 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003852 * Optimization: Create an equally sized node-set
3853 * and memcpy the content.
3854 */
3855 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3856 if (val1 == NULL)
3857 return(NULL);
3858 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003859 if (val2->nodeNr == 1)
3860 *(val1->nodeTab) = *(val2->nodeTab);
3861 else {
3862 memcpy(val1->nodeTab, val2->nodeTab,
3863 val2->nodeNr * sizeof(xmlNodePtr));
3864 }
3865 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003866 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003867 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003868#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003869 }
3870
William M. Brack08171912003-12-29 02:52:11 +00003871 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003872 initNr = val1->nodeNr;
3873
3874 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003875 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003876 /*
William M. Brack08171912003-12-29 02:52:11 +00003877 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003878 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003879 skip = 0;
3880 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003881 n1 = val1->nodeTab[j];
3882 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003883 skip = 1;
3884 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003885 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003886 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003887 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3888 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3889 ((xmlNsPtr) n2)->prefix)))
3890 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003891 skip = 1;
3892 break;
3893 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003894 }
3895 }
3896 if (skip)
3897 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003898
3899 /*
3900 * grow the nodeTab if needed
3901 */
3902 if (val1->nodeMax == 0) {
3903 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3904 sizeof(xmlNodePtr));
3905 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003906 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003907 return(NULL);
3908 }
3909 memset(val1->nodeTab, 0 ,
3910 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3911 val1->nodeMax = XML_NODESET_DEFAULT;
3912 } else if (val1->nodeNr == val1->nodeMax) {
3913 xmlNodePtr *temp;
3914
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003915 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3916 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3917 return(NULL);
3918 }
Chris Evansd7958b22011-03-23 08:13:06 +08003919 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003920 sizeof(xmlNodePtr));
3921 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003922 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003923 return(NULL);
3924 }
3925 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003926 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003927 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003928 if (n2->type == XML_NAMESPACE_DECL) {
3929 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003930
3931 val1->nodeTab[val1->nodeNr++] =
3932 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3933 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003934 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003935 }
3936
3937 return(val1);
3938}
3939
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003940
3941/**
3942 * xmlXPathNodeSetMergeAndClear:
3943 * @set1: the first NodeSet or NULL
3944 * @set2: the second NodeSet
3945 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3946 *
3947 * Merges two nodesets, all nodes from @set2 are added to @set1
3948 * if @set1 is NULL, a new set is created and copied from @set2.
3949 * Checks for duplicate nodes. Clears set2.
3950 *
3951 * Returns @set1 once extended or NULL in case of error.
3952 */
3953static xmlNodeSetPtr
3954xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3955 int hasNullEntries)
3956{
3957 if ((set1 == NULL) && (hasNullEntries == 0)) {
3958 /*
3959 * Note that doing a memcpy of the list, namespace nodes are
3960 * just assigned to set1, since set2 is cleared anyway.
3961 */
3962 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3963 if (set1 == NULL)
3964 return(NULL);
3965 if (set2->nodeNr != 0) {
3966 memcpy(set1->nodeTab, set2->nodeTab,
3967 set2->nodeNr * sizeof(xmlNodePtr));
3968 set1->nodeNr = set2->nodeNr;
3969 }
3970 } else {
3971 int i, j, initNbSet1;
3972 xmlNodePtr n1, n2;
3973
3974 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003975 set1 = xmlXPathNodeSetCreate(NULL);
3976 if (set1 == NULL)
3977 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003978
Daniel Veillard45490ae2008-07-29 09:13:19 +00003979 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003980 for (i = 0;i < set2->nodeNr;i++) {
3981 n2 = set2->nodeTab[i];
3982 /*
3983 * Skip NULLed entries.
3984 */
3985 if (n2 == NULL)
3986 continue;
3987 /*
3988 * Skip duplicates.
3989 */
3990 for (j = 0; j < initNbSet1; j++) {
3991 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003992 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003993 goto skip_node;
3994 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3995 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003996 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003997 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3998 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3999 ((xmlNsPtr) n2)->prefix)))
4000 {
4001 /*
4002 * Free the namespace node.
4003 */
4004 set2->nodeTab[i] = NULL;
4005 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
4006 goto skip_node;
4007 }
4008 }
4009 }
4010 /*
4011 * grow the nodeTab if needed
4012 */
4013 if (set1->nodeMax == 0) {
4014 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4015 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4016 if (set1->nodeTab == NULL) {
4017 xmlXPathErrMemory(NULL, "merging nodeset\n");
4018 return(NULL);
4019 }
4020 memset(set1->nodeTab, 0,
4021 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4022 set1->nodeMax = XML_NODESET_DEFAULT;
4023 } else if (set1->nodeNr >= set1->nodeMax) {
4024 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004025
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004026 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4027 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4028 return(NULL);
4029 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004030 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004031 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004032 if (temp == NULL) {
4033 xmlXPathErrMemory(NULL, "merging nodeset\n");
4034 return(NULL);
4035 }
4036 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004037 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004038 }
Nick Wellnhofer9d08b342017-05-21 16:46:12 +02004039 set1->nodeTab[set1->nodeNr++] = n2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004040skip_node:
4041 {}
4042 }
4043 }
4044 set2->nodeNr = 0;
4045 return(set1);
4046}
4047
4048/**
4049 * xmlXPathNodeSetMergeAndClearNoDupls:
4050 * @set1: the first NodeSet or NULL
4051 * @set2: the second NodeSet
4052 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4053 *
4054 * Merges two nodesets, all nodes from @set2 are added to @set1
4055 * if @set1 is NULL, a new set is created and copied from @set2.
4056 * Doesn't chack for duplicate nodes. Clears set2.
4057 *
4058 * Returns @set1 once extended or NULL in case of error.
4059 */
4060static xmlNodeSetPtr
4061xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4062 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004063{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004064 if (set2 == NULL)
4065 return(set1);
4066 if ((set1 == NULL) && (hasNullEntries == 0)) {
4067 /*
4068 * Note that doing a memcpy of the list, namespace nodes are
4069 * just assigned to set1, since set2 is cleared anyway.
4070 */
4071 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4072 if (set1 == NULL)
4073 return(NULL);
4074 if (set2->nodeNr != 0) {
4075 memcpy(set1->nodeTab, set2->nodeTab,
4076 set2->nodeNr * sizeof(xmlNodePtr));
4077 set1->nodeNr = set2->nodeNr;
4078 }
4079 } else {
4080 int i;
4081 xmlNodePtr n2;
4082
4083 if (set1 == NULL)
4084 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004085 if (set1 == NULL)
4086 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004087
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004088 for (i = 0;i < set2->nodeNr;i++) {
4089 n2 = set2->nodeTab[i];
4090 /*
4091 * Skip NULLed entries.
4092 */
4093 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004094 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004095 if (set1->nodeMax == 0) {
4096 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4097 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4098 if (set1->nodeTab == NULL) {
4099 xmlXPathErrMemory(NULL, "merging nodeset\n");
4100 return(NULL);
4101 }
4102 memset(set1->nodeTab, 0,
4103 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4104 set1->nodeMax = XML_NODESET_DEFAULT;
4105 } else if (set1->nodeNr >= set1->nodeMax) {
4106 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004107
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004108 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4109 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4110 return(NULL);
4111 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004112 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004113 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004114 if (temp == NULL) {
4115 xmlXPathErrMemory(NULL, "merging nodeset\n");
4116 return(NULL);
4117 }
4118 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004119 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004120 }
4121 set1->nodeTab[set1->nodeNr++] = n2;
4122 }
4123 }
4124 set2->nodeNr = 0;
4125 return(set1);
4126}
Daniel Veillard75be0132002-03-13 10:03:35 +00004127
4128/**
Owen Taylor3473f882001-02-23 17:55:21 +00004129 * xmlXPathNodeSetDel:
4130 * @cur: the initial node set
4131 * @val: an xmlNodePtr
4132 *
4133 * Removes an xmlNodePtr from an existing NodeSet
4134 */
4135void
4136xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4137 int i;
4138
4139 if (cur == NULL) return;
4140 if (val == NULL) return;
4141
4142 /*
William M. Brack08171912003-12-29 02:52:11 +00004143 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004144 */
4145 for (i = 0;i < cur->nodeNr;i++)
4146 if (cur->nodeTab[i] == val) break;
4147
William M. Brack08171912003-12-29 02:52:11 +00004148 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004149#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004150 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004151 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4152 val->name);
4153#endif
4154 return;
4155 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004156 if ((cur->nodeTab[i] != NULL) &&
4157 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4158 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004159 cur->nodeNr--;
4160 for (;i < cur->nodeNr;i++)
4161 cur->nodeTab[i] = cur->nodeTab[i + 1];
4162 cur->nodeTab[cur->nodeNr] = NULL;
4163}
4164
4165/**
4166 * xmlXPathNodeSetRemove:
4167 * @cur: the initial node set
4168 * @val: the index to remove
4169 *
4170 * Removes an entry from an existing NodeSet list.
4171 */
4172void
4173xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4174 if (cur == NULL) return;
4175 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004176 if ((cur->nodeTab[val] != NULL) &&
4177 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4178 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004179 cur->nodeNr--;
4180 for (;val < cur->nodeNr;val++)
4181 cur->nodeTab[val] = cur->nodeTab[val + 1];
4182 cur->nodeTab[cur->nodeNr] = NULL;
4183}
4184
4185/**
4186 * xmlXPathFreeNodeSet:
4187 * @obj: the xmlNodeSetPtr to free
4188 *
4189 * Free the NodeSet compound (not the actual nodes !).
4190 */
4191void
4192xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4193 if (obj == NULL) return;
4194 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004195 int i;
4196
William M. Brack08171912003-12-29 02:52:11 +00004197 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004198 for (i = 0;i < obj->nodeNr;i++)
4199 if ((obj->nodeTab[i] != NULL) &&
4200 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4201 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004202 xmlFree(obj->nodeTab);
4203 }
Owen Taylor3473f882001-02-23 17:55:21 +00004204 xmlFree(obj);
4205}
4206
4207/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004208 * xmlXPathNodeSetClearFromPos:
4209 * @set: the node set to be cleared
4210 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004211 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004212 * Clears the list from temporary XPath objects (e.g. namespace nodes
4213 * are feed) starting with the entry at @pos, but does *not* free the list
4214 * itself. Sets the length of the list to @pos.
4215 */
4216static void
4217xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4218{
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004219 if ((set == NULL) || (pos >= set->nodeNr))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004220 return;
4221 else if ((hasNsNodes)) {
4222 int i;
4223 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004224
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004225 for (i = pos; i < set->nodeNr; i++) {
4226 node = set->nodeTab[i];
4227 if ((node != NULL) &&
4228 (node->type == XML_NAMESPACE_DECL))
4229 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004230 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004231 }
4232 set->nodeNr = pos;
4233}
4234
4235/**
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004236 * xmlXPathNodeSetClear:
4237 * @set: the node set to clear
4238 *
4239 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4240 * are feed), but does *not* free the list itself. Sets the length of the
4241 * list to 0.
4242 */
4243static void
4244xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4245{
4246 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4247}
4248
4249/**
4250 * xmlXPathNodeSetKeepLast:
4251 * @set: the node set to be cleared
4252 *
4253 * Move the last node to the first position and clear temporary XPath objects
4254 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4255 * to 1.
4256 */
4257static void
4258xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4259{
4260 int i;
4261 xmlNodePtr node;
4262
4263 if ((set == NULL) || (set->nodeNr <= 1))
4264 return;
4265 for (i = 0; i < set->nodeNr - 1; i++) {
4266 node = set->nodeTab[i];
4267 if ((node != NULL) &&
4268 (node->type == XML_NAMESPACE_DECL))
4269 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4270 }
4271 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4272 set->nodeNr = 1;
4273}
4274
4275/**
Owen Taylor3473f882001-02-23 17:55:21 +00004276 * xmlXPathFreeValueTree:
4277 * @obj: the xmlNodeSetPtr to free
4278 *
4279 * Free the NodeSet compound and the actual tree, this is different
4280 * from xmlXPathFreeNodeSet()
4281 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004282static void
Owen Taylor3473f882001-02-23 17:55:21 +00004283xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4284 int i;
4285
4286 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004287
4288 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004289 for (i = 0;i < obj->nodeNr;i++) {
4290 if (obj->nodeTab[i] != NULL) {
4291 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4292 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4293 } else {
4294 xmlFreeNodeList(obj->nodeTab[i]);
4295 }
4296 }
4297 }
Owen Taylor3473f882001-02-23 17:55:21 +00004298 xmlFree(obj->nodeTab);
4299 }
Owen Taylor3473f882001-02-23 17:55:21 +00004300 xmlFree(obj);
4301}
4302
4303#if defined(DEBUG) || defined(DEBUG_STEP)
4304/**
4305 * xmlGenericErrorContextNodeSet:
4306 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004307 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004308 *
4309 * Quick display of a NodeSet
4310 */
4311void
4312xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4313 int i;
4314
4315 if (output == NULL) output = xmlGenericErrorContext;
4316 if (obj == NULL) {
4317 fprintf(output, "NodeSet == NULL !\n");
4318 return;
4319 }
4320 if (obj->nodeNr == 0) {
4321 fprintf(output, "NodeSet is empty\n");
4322 return;
4323 }
4324 if (obj->nodeTab == NULL) {
4325 fprintf(output, " nodeTab == NULL !\n");
4326 return;
4327 }
4328 for (i = 0; i < obj->nodeNr; i++) {
4329 if (obj->nodeTab[i] == NULL) {
4330 fprintf(output, " NULL !\n");
4331 return;
4332 }
4333 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4334 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4335 fprintf(output, " /");
4336 else if (obj->nodeTab[i]->name == NULL)
4337 fprintf(output, " noname!");
4338 else fprintf(output, " %s", obj->nodeTab[i]->name);
4339 }
4340 fprintf(output, "\n");
4341}
4342#endif
4343
4344/**
4345 * xmlXPathNewNodeSet:
4346 * @val: the NodePtr value
4347 *
4348 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4349 * it with the single Node @val
4350 *
4351 * Returns the newly created object.
4352 */
4353xmlXPathObjectPtr
4354xmlXPathNewNodeSet(xmlNodePtr val) {
4355 xmlXPathObjectPtr ret;
4356
4357 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4358 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004359 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004360 return(NULL);
4361 }
4362 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4363 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004364 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004365 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004366 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004367#ifdef XP_DEBUG_OBJ_USAGE
4368 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4369#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004370 return(ret);
4371}
4372
4373/**
4374 * xmlXPathNewValueTree:
4375 * @val: the NodePtr value
4376 *
4377 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4378 * it with the tree root @val
4379 *
4380 * Returns the newly created object.
4381 */
4382xmlXPathObjectPtr
4383xmlXPathNewValueTree(xmlNodePtr val) {
4384 xmlXPathObjectPtr ret;
4385
4386 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4387 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004388 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004389 return(NULL);
4390 }
4391 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4392 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004393 ret->boolval = 1;
4394 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004395 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004396#ifdef XP_DEBUG_OBJ_USAGE
4397 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4398#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004399 return(ret);
4400}
4401
4402/**
4403 * xmlXPathNewNodeSetList:
4404 * @val: an existing NodeSet
4405 *
4406 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4407 * it with the Nodeset @val
4408 *
4409 * Returns the newly created object.
4410 */
4411xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004412xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4413{
Owen Taylor3473f882001-02-23 17:55:21 +00004414 xmlXPathObjectPtr ret;
4415 int i;
4416
4417 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004418 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004419 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004420 ret = xmlXPathNewNodeSet(NULL);
4421 else {
4422 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004423 if (ret) {
4424 for (i = 1; i < val->nodeNr; ++i) {
4425 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4426 < 0) break;
4427 }
4428 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004429 }
Owen Taylor3473f882001-02-23 17:55:21 +00004430
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004431 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004432}
4433
4434/**
4435 * xmlXPathWrapNodeSet:
4436 * @val: the NodePtr value
4437 *
4438 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4439 *
4440 * Returns the newly created object.
4441 */
4442xmlXPathObjectPtr
4443xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4444 xmlXPathObjectPtr ret;
4445
4446 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4447 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004448 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004449 return(NULL);
4450 }
4451 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4452 ret->type = XPATH_NODESET;
4453 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004454#ifdef XP_DEBUG_OBJ_USAGE
4455 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4456#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004457 return(ret);
4458}
4459
4460/**
4461 * xmlXPathFreeNodeSetList:
4462 * @obj: an existing NodeSetList object
4463 *
4464 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4465 * the list contrary to xmlXPathFreeObject().
4466 */
4467void
4468xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4469 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004470#ifdef XP_DEBUG_OBJ_USAGE
4471 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4472#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004473 xmlFree(obj);
4474}
4475
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004476/**
4477 * xmlXPathDifference:
4478 * @nodes1: a node-set
4479 * @nodes2: a node-set
4480 *
4481 * Implements the EXSLT - Sets difference() function:
4482 * node-set set:difference (node-set, node-set)
4483 *
4484 * Returns the difference between the two node sets, or nodes1 if
4485 * nodes2 is empty
4486 */
4487xmlNodeSetPtr
4488xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4489 xmlNodeSetPtr ret;
4490 int i, l1;
4491 xmlNodePtr cur;
4492
4493 if (xmlXPathNodeSetIsEmpty(nodes2))
4494 return(nodes1);
4495
4496 ret = xmlXPathNodeSetCreate(NULL);
4497 if (xmlXPathNodeSetIsEmpty(nodes1))
4498 return(ret);
4499
4500 l1 = xmlXPathNodeSetGetLength(nodes1);
4501
4502 for (i = 0; i < l1; i++) {
4503 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004504 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4505 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4506 break;
4507 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004508 }
4509 return(ret);
4510}
4511
4512/**
4513 * xmlXPathIntersection:
4514 * @nodes1: a node-set
4515 * @nodes2: a node-set
4516 *
4517 * Implements the EXSLT - Sets intersection() function:
4518 * node-set set:intersection (node-set, node-set)
4519 *
4520 * Returns a node set comprising the nodes that are within both the
4521 * node sets passed as arguments
4522 */
4523xmlNodeSetPtr
4524xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4525 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4526 int i, l1;
4527 xmlNodePtr cur;
4528
Daniel Veillardf88d8492008-04-01 08:00:31 +00004529 if (ret == NULL)
4530 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004531 if (xmlXPathNodeSetIsEmpty(nodes1))
4532 return(ret);
4533 if (xmlXPathNodeSetIsEmpty(nodes2))
4534 return(ret);
4535
4536 l1 = xmlXPathNodeSetGetLength(nodes1);
4537
4538 for (i = 0; i < l1; i++) {
4539 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004540 if (xmlXPathNodeSetContains(nodes2, cur)) {
4541 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4542 break;
4543 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004544 }
4545 return(ret);
4546}
4547
4548/**
4549 * xmlXPathDistinctSorted:
4550 * @nodes: a node-set, sorted by document order
4551 *
4552 * Implements the EXSLT - Sets distinct() function:
4553 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004554 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004555 * Returns a subset of the nodes contained in @nodes, or @nodes if
4556 * it is empty
4557 */
4558xmlNodeSetPtr
4559xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4560 xmlNodeSetPtr ret;
4561 xmlHashTablePtr hash;
4562 int i, l;
4563 xmlChar * strval;
4564 xmlNodePtr cur;
4565
4566 if (xmlXPathNodeSetIsEmpty(nodes))
4567 return(nodes);
4568
4569 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004570 if (ret == NULL)
4571 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004572 l = xmlXPathNodeSetGetLength(nodes);
4573 hash = xmlHashCreate (l);
4574 for (i = 0; i < l; i++) {
4575 cur = xmlXPathNodeSetItem(nodes, i);
4576 strval = xmlXPathCastNodeToString(cur);
4577 if (xmlHashLookup(hash, strval) == NULL) {
4578 xmlHashAddEntry(hash, strval, strval);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004579 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4580 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004581 } else {
4582 xmlFree(strval);
4583 }
4584 }
4585 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4586 return(ret);
4587}
4588
4589/**
4590 * xmlXPathDistinct:
4591 * @nodes: a node-set
4592 *
4593 * Implements the EXSLT - Sets distinct() function:
4594 * node-set set:distinct (node-set)
4595 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4596 * is called with the sorted node-set
4597 *
4598 * Returns a subset of the nodes contained in @nodes, or @nodes if
4599 * it is empty
4600 */
4601xmlNodeSetPtr
4602xmlXPathDistinct (xmlNodeSetPtr nodes) {
4603 if (xmlXPathNodeSetIsEmpty(nodes))
4604 return(nodes);
4605
4606 xmlXPathNodeSetSort(nodes);
4607 return(xmlXPathDistinctSorted(nodes));
4608}
4609
4610/**
4611 * xmlXPathHasSameNodes:
4612 * @nodes1: a node-set
4613 * @nodes2: a node-set
4614 *
4615 * Implements the EXSLT - Sets has-same-nodes function:
4616 * boolean set:has-same-node(node-set, node-set)
4617 *
4618 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4619 * otherwise
4620 */
4621int
4622xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4623 int i, l;
4624 xmlNodePtr cur;
4625
4626 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4627 xmlXPathNodeSetIsEmpty(nodes2))
4628 return(0);
4629
4630 l = xmlXPathNodeSetGetLength(nodes1);
4631 for (i = 0; i < l; i++) {
4632 cur = xmlXPathNodeSetItem(nodes1, i);
4633 if (xmlXPathNodeSetContains(nodes2, cur))
4634 return(1);
4635 }
4636 return(0);
4637}
4638
4639/**
4640 * xmlXPathNodeLeadingSorted:
4641 * @nodes: a node-set, sorted by document order
4642 * @node: a node
4643 *
4644 * Implements the EXSLT - Sets leading() function:
4645 * node-set set:leading (node-set, node-set)
4646 *
4647 * Returns the nodes in @nodes that precede @node in document order,
4648 * @nodes if @node is NULL or an empty node-set if @nodes
4649 * doesn't contain @node
4650 */
4651xmlNodeSetPtr
4652xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4653 int i, l;
4654 xmlNodePtr cur;
4655 xmlNodeSetPtr ret;
4656
4657 if (node == NULL)
4658 return(nodes);
4659
4660 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004661 if (ret == NULL)
4662 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004663 if (xmlXPathNodeSetIsEmpty(nodes) ||
4664 (!xmlXPathNodeSetContains(nodes, node)))
4665 return(ret);
4666
4667 l = xmlXPathNodeSetGetLength(nodes);
4668 for (i = 0; i < l; i++) {
4669 cur = xmlXPathNodeSetItem(nodes, i);
4670 if (cur == node)
4671 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004672 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4673 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004674 }
4675 return(ret);
4676}
4677
4678/**
4679 * xmlXPathNodeLeading:
4680 * @nodes: a node-set
4681 * @node: a node
4682 *
4683 * Implements the EXSLT - Sets leading() function:
4684 * node-set set:leading (node-set, node-set)
4685 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4686 * is called.
4687 *
4688 * Returns the nodes in @nodes that precede @node in document order,
4689 * @nodes if @node is NULL or an empty node-set if @nodes
4690 * doesn't contain @node
4691 */
4692xmlNodeSetPtr
4693xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4694 xmlXPathNodeSetSort(nodes);
4695 return(xmlXPathNodeLeadingSorted(nodes, node));
4696}
4697
4698/**
4699 * xmlXPathLeadingSorted:
4700 * @nodes1: a node-set, sorted by document order
4701 * @nodes2: a node-set, sorted by document order
4702 *
4703 * Implements the EXSLT - Sets leading() function:
4704 * node-set set:leading (node-set, node-set)
4705 *
4706 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4707 * in document order, @nodes1 if @nodes2 is NULL or empty or
4708 * an empty node-set if @nodes1 doesn't contain @nodes2
4709 */
4710xmlNodeSetPtr
4711xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4712 if (xmlXPathNodeSetIsEmpty(nodes2))
4713 return(nodes1);
4714 return(xmlXPathNodeLeadingSorted(nodes1,
4715 xmlXPathNodeSetItem(nodes2, 1)));
4716}
4717
4718/**
4719 * xmlXPathLeading:
4720 * @nodes1: a node-set
4721 * @nodes2: a node-set
4722 *
4723 * Implements the EXSLT - Sets leading() function:
4724 * node-set set:leading (node-set, node-set)
4725 * @nodes1 and @nodes2 are sorted by document order, then
4726 * #exslSetsLeadingSorted is called.
4727 *
4728 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4729 * in document order, @nodes1 if @nodes2 is NULL or empty or
4730 * an empty node-set if @nodes1 doesn't contain @nodes2
4731 */
4732xmlNodeSetPtr
4733xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4734 if (xmlXPathNodeSetIsEmpty(nodes2))
4735 return(nodes1);
4736 if (xmlXPathNodeSetIsEmpty(nodes1))
4737 return(xmlXPathNodeSetCreate(NULL));
4738 xmlXPathNodeSetSort(nodes1);
4739 xmlXPathNodeSetSort(nodes2);
4740 return(xmlXPathNodeLeadingSorted(nodes1,
4741 xmlXPathNodeSetItem(nodes2, 1)));
4742}
4743
4744/**
4745 * xmlXPathNodeTrailingSorted:
4746 * @nodes: a node-set, sorted by document order
4747 * @node: a node
4748 *
4749 * Implements the EXSLT - Sets trailing() function:
4750 * node-set set:trailing (node-set, node-set)
4751 *
4752 * Returns the nodes in @nodes that follow @node in document order,
4753 * @nodes if @node is NULL or an empty node-set if @nodes
4754 * doesn't contain @node
4755 */
4756xmlNodeSetPtr
4757xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4758 int i, l;
4759 xmlNodePtr cur;
4760 xmlNodeSetPtr ret;
4761
4762 if (node == NULL)
4763 return(nodes);
4764
4765 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004766 if (ret == NULL)
4767 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004768 if (xmlXPathNodeSetIsEmpty(nodes) ||
4769 (!xmlXPathNodeSetContains(nodes, node)))
4770 return(ret);
4771
4772 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004773 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004774 cur = xmlXPathNodeSetItem(nodes, i);
4775 if (cur == node)
4776 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004777 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4778 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004779 }
William M. Brack97ac8192007-06-06 17:19:24 +00004780 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004781 return(ret);
4782}
4783
4784/**
4785 * xmlXPathNodeTrailing:
4786 * @nodes: a node-set
4787 * @node: a node
4788 *
4789 * Implements the EXSLT - Sets trailing() function:
4790 * node-set set:trailing (node-set, node-set)
4791 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4792 * is called.
4793 *
4794 * Returns the nodes in @nodes that follow @node in document order,
4795 * @nodes if @node is NULL or an empty node-set if @nodes
4796 * doesn't contain @node
4797 */
4798xmlNodeSetPtr
4799xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4800 xmlXPathNodeSetSort(nodes);
4801 return(xmlXPathNodeTrailingSorted(nodes, node));
4802}
4803
4804/**
4805 * xmlXPathTrailingSorted:
4806 * @nodes1: a node-set, sorted by document order
4807 * @nodes2: a node-set, sorted by document order
4808 *
4809 * Implements the EXSLT - Sets trailing() function:
4810 * node-set set:trailing (node-set, node-set)
4811 *
4812 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4813 * in document order, @nodes1 if @nodes2 is NULL or empty or
4814 * an empty node-set if @nodes1 doesn't contain @nodes2
4815 */
4816xmlNodeSetPtr
4817xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4818 if (xmlXPathNodeSetIsEmpty(nodes2))
4819 return(nodes1);
4820 return(xmlXPathNodeTrailingSorted(nodes1,
4821 xmlXPathNodeSetItem(nodes2, 0)));
4822}
4823
4824/**
4825 * xmlXPathTrailing:
4826 * @nodes1: a node-set
4827 * @nodes2: a node-set
4828 *
4829 * Implements the EXSLT - Sets trailing() function:
4830 * node-set set:trailing (node-set, node-set)
4831 * @nodes1 and @nodes2 are sorted by document order, then
4832 * #xmlXPathTrailingSorted is called.
4833 *
4834 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4835 * in document order, @nodes1 if @nodes2 is NULL or empty or
4836 * an empty node-set if @nodes1 doesn't contain @nodes2
4837 */
4838xmlNodeSetPtr
4839xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4840 if (xmlXPathNodeSetIsEmpty(nodes2))
4841 return(nodes1);
4842 if (xmlXPathNodeSetIsEmpty(nodes1))
4843 return(xmlXPathNodeSetCreate(NULL));
4844 xmlXPathNodeSetSort(nodes1);
4845 xmlXPathNodeSetSort(nodes2);
4846 return(xmlXPathNodeTrailingSorted(nodes1,
4847 xmlXPathNodeSetItem(nodes2, 0)));
4848}
4849
Owen Taylor3473f882001-02-23 17:55:21 +00004850/************************************************************************
4851 * *
4852 * Routines to handle extra functions *
4853 * *
4854 ************************************************************************/
4855
4856/**
4857 * xmlXPathRegisterFunc:
4858 * @ctxt: the XPath context
4859 * @name: the function name
4860 * @f: the function implementation or NULL
4861 *
4862 * Register a new function. If @f is NULL it unregisters the function
4863 *
4864 * Returns 0 in case of success, -1 in case of error
4865 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004866int
Owen Taylor3473f882001-02-23 17:55:21 +00004867xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4868 xmlXPathFunction f) {
4869 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4870}
4871
4872/**
4873 * xmlXPathRegisterFuncNS:
4874 * @ctxt: the XPath context
4875 * @name: the function name
4876 * @ns_uri: the function namespace URI
4877 * @f: the function implementation or NULL
4878 *
4879 * Register a new function. If @f is NULL it unregisters the function
4880 *
4881 * Returns 0 in case of success, -1 in case of error
4882 */
4883int
4884xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4885 const xmlChar *ns_uri, xmlXPathFunction f) {
4886 if (ctxt == NULL)
4887 return(-1);
4888 if (name == NULL)
4889 return(-1);
4890
4891 if (ctxt->funcHash == NULL)
4892 ctxt->funcHash = xmlHashCreate(0);
4893 if (ctxt->funcHash == NULL)
4894 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004895 if (f == NULL)
4896 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004897 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004898}
4899
4900/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004901 * xmlXPathRegisterFuncLookup:
4902 * @ctxt: the XPath context
4903 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004904 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004905 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004906 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004907 */
4908void
4909xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4910 xmlXPathFuncLookupFunc f,
4911 void *funcCtxt) {
4912 if (ctxt == NULL)
4913 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004914 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004915 ctxt->funcLookupData = funcCtxt;
4916}
4917
4918/**
Owen Taylor3473f882001-02-23 17:55:21 +00004919 * xmlXPathFunctionLookup:
4920 * @ctxt: the XPath context
4921 * @name: the function name
4922 *
4923 * Search in the Function array of the context for the given
4924 * function.
4925 *
4926 * Returns the xmlXPathFunction or NULL if not found
4927 */
4928xmlXPathFunction
4929xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004930 if (ctxt == NULL)
4931 return (NULL);
4932
4933 if (ctxt->funcLookupFunc != NULL) {
4934 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004935 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004936
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004937 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004938 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004939 if (ret != NULL)
4940 return(ret);
4941 }
Owen Taylor3473f882001-02-23 17:55:21 +00004942 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4943}
4944
4945/**
4946 * xmlXPathFunctionLookupNS:
4947 * @ctxt: the XPath context
4948 * @name: the function name
4949 * @ns_uri: the function namespace URI
4950 *
4951 * Search in the Function array of the context for the given
4952 * function.
4953 *
4954 * Returns the xmlXPathFunction or NULL if not found
4955 */
4956xmlXPathFunction
4957xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4958 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004959 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004960
Owen Taylor3473f882001-02-23 17:55:21 +00004961 if (ctxt == NULL)
4962 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004963 if (name == NULL)
4964 return(NULL);
4965
Thomas Broyerba4ad322001-07-26 16:55:21 +00004966 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004967 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004968
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004969 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004970 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004971 if (ret != NULL)
4972 return(ret);
4973 }
4974
4975 if (ctxt->funcHash == NULL)
4976 return(NULL);
4977
William M. Brackad0e67c2004-12-01 14:35:10 +00004978 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4979 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004980}
4981
4982/**
4983 * xmlXPathRegisteredFuncsCleanup:
4984 * @ctxt: the XPath context
4985 *
4986 * Cleanup the XPath context data associated to registered functions
4987 */
4988void
4989xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4990 if (ctxt == NULL)
4991 return;
4992
4993 xmlHashFree(ctxt->funcHash, NULL);
4994 ctxt->funcHash = NULL;
4995}
4996
4997/************************************************************************
4998 * *
William M. Brack08171912003-12-29 02:52:11 +00004999 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00005000 * *
5001 ************************************************************************/
5002
5003/**
5004 * xmlXPathRegisterVariable:
5005 * @ctxt: the XPath context
5006 * @name: the variable name
5007 * @value: the variable value or NULL
5008 *
5009 * Register a new variable value. If @value is NULL it unregisters
5010 * the variable
5011 *
5012 * Returns 0 in case of success, -1 in case of error
5013 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00005014int
Owen Taylor3473f882001-02-23 17:55:21 +00005015xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5016 xmlXPathObjectPtr value) {
5017 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5018}
5019
5020/**
5021 * xmlXPathRegisterVariableNS:
5022 * @ctxt: the XPath context
5023 * @name: the variable name
5024 * @ns_uri: the variable namespace URI
5025 * @value: the variable value or NULL
5026 *
5027 * Register a new variable value. If @value is NULL it unregisters
5028 * the variable
5029 *
5030 * Returns 0 in case of success, -1 in case of error
5031 */
5032int
5033xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5034 const xmlChar *ns_uri,
5035 xmlXPathObjectPtr value) {
5036 if (ctxt == NULL)
5037 return(-1);
5038 if (name == NULL)
5039 return(-1);
5040
5041 if (ctxt->varHash == NULL)
5042 ctxt->varHash = xmlHashCreate(0);
5043 if (ctxt->varHash == NULL)
5044 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00005045 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005046 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00005047 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00005048 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5049 (void *) value,
5050 (xmlHashDeallocator)xmlXPathFreeObject));
5051}
5052
5053/**
5054 * xmlXPathRegisterVariableLookup:
5055 * @ctxt: the XPath context
5056 * @f: the lookup function
5057 * @data: the lookup data
5058 *
5059 * register an external mechanism to do variable lookup
5060 */
5061void
5062xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5063 xmlXPathVariableLookupFunc f, void *data) {
5064 if (ctxt == NULL)
5065 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00005066 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00005067 ctxt->varLookupData = data;
5068}
5069
5070/**
5071 * xmlXPathVariableLookup:
5072 * @ctxt: the XPath context
5073 * @name: the variable name
5074 *
5075 * Search in the Variable array of the context for the given
5076 * variable value.
5077 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005078 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005079 */
5080xmlXPathObjectPtr
5081xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5082 if (ctxt == NULL)
5083 return(NULL);
5084
5085 if (ctxt->varLookupFunc != NULL) {
5086 xmlXPathObjectPtr ret;
5087
5088 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5089 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00005090 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005091 }
5092 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5093}
5094
5095/**
5096 * xmlXPathVariableLookupNS:
5097 * @ctxt: the XPath context
5098 * @name: the variable name
5099 * @ns_uri: the variable namespace URI
5100 *
5101 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005102 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005103 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005104 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005105 */
5106xmlXPathObjectPtr
5107xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5108 const xmlChar *ns_uri) {
5109 if (ctxt == NULL)
5110 return(NULL);
5111
5112 if (ctxt->varLookupFunc != NULL) {
5113 xmlXPathObjectPtr ret;
5114
5115 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5116 (ctxt->varLookupData, name, ns_uri);
5117 if (ret != NULL) return(ret);
5118 }
5119
5120 if (ctxt->varHash == NULL)
5121 return(NULL);
5122 if (name == NULL)
5123 return(NULL);
5124
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005125 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005126 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005127}
5128
5129/**
5130 * xmlXPathRegisteredVariablesCleanup:
5131 * @ctxt: the XPath context
5132 *
5133 * Cleanup the XPath context data associated to registered variables
5134 */
5135void
5136xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5137 if (ctxt == NULL)
5138 return;
5139
Daniel Veillard76d66f42001-05-16 21:05:17 +00005140 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005141 ctxt->varHash = NULL;
5142}
5143
5144/**
5145 * xmlXPathRegisterNs:
5146 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005147 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005148 * @ns_uri: the namespace name
5149 *
5150 * Register a new namespace. If @ns_uri is NULL it unregisters
5151 * the namespace
5152 *
5153 * Returns 0 in case of success, -1 in case of error
5154 */
5155int
5156xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5157 const xmlChar *ns_uri) {
5158 if (ctxt == NULL)
5159 return(-1);
5160 if (prefix == NULL)
5161 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005162 if (prefix[0] == 0)
5163 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005164
5165 if (ctxt->nsHash == NULL)
5166 ctxt->nsHash = xmlHashCreate(10);
5167 if (ctxt->nsHash == NULL)
5168 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005169 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005170 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005171 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005172 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005173 (xmlHashDeallocator)xmlFree));
5174}
5175
5176/**
5177 * xmlXPathNsLookup:
5178 * @ctxt: the XPath context
5179 * @prefix: the namespace prefix value
5180 *
5181 * Search in the namespace declaration array of the context for the given
5182 * namespace name associated to the given prefix
5183 *
5184 * Returns the value or NULL if not found
5185 */
5186const xmlChar *
5187xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5188 if (ctxt == NULL)
5189 return(NULL);
5190 if (prefix == NULL)
5191 return(NULL);
5192
5193#ifdef XML_XML_NAMESPACE
5194 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5195 return(XML_XML_NAMESPACE);
5196#endif
5197
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005198 if (ctxt->namespaces != NULL) {
5199 int i;
5200
5201 for (i = 0;i < ctxt->nsNr;i++) {
5202 if ((ctxt->namespaces[i] != NULL) &&
5203 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5204 return(ctxt->namespaces[i]->href);
5205 }
5206 }
Owen Taylor3473f882001-02-23 17:55:21 +00005207
5208 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5209}
5210
5211/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005212 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005213 * @ctxt: the XPath context
5214 *
5215 * Cleanup the XPath context data associated to registered variables
5216 */
5217void
5218xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5219 if (ctxt == NULL)
5220 return;
5221
Daniel Veillard42766c02002-08-22 20:52:17 +00005222 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005223 ctxt->nsHash = NULL;
5224}
5225
5226/************************************************************************
5227 * *
5228 * Routines to handle Values *
5229 * *
5230 ************************************************************************/
5231
William M. Brack08171912003-12-29 02:52:11 +00005232/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005233
5234/**
5235 * xmlXPathNewFloat:
5236 * @val: the double value
5237 *
5238 * Create a new xmlXPathObjectPtr of type double and of value @val
5239 *
5240 * Returns the newly created object.
5241 */
5242xmlXPathObjectPtr
5243xmlXPathNewFloat(double val) {
5244 xmlXPathObjectPtr ret;
5245
5246 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005248 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005249 return(NULL);
5250 }
5251 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5252 ret->type = XPATH_NUMBER;
5253 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005254#ifdef XP_DEBUG_OBJ_USAGE
5255 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5256#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005257 return(ret);
5258}
5259
5260/**
5261 * xmlXPathNewBoolean:
5262 * @val: the boolean value
5263 *
5264 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5265 *
5266 * Returns the newly created object.
5267 */
5268xmlXPathObjectPtr
5269xmlXPathNewBoolean(int val) {
5270 xmlXPathObjectPtr ret;
5271
5272 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5273 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005274 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005275 return(NULL);
5276 }
5277 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5278 ret->type = XPATH_BOOLEAN;
5279 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005280#ifdef XP_DEBUG_OBJ_USAGE
5281 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5282#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005283 return(ret);
5284}
5285
5286/**
5287 * xmlXPathNewString:
5288 * @val: the xmlChar * value
5289 *
5290 * Create a new xmlXPathObjectPtr of type string and of value @val
5291 *
5292 * Returns the newly created object.
5293 */
5294xmlXPathObjectPtr
5295xmlXPathNewString(const xmlChar *val) {
5296 xmlXPathObjectPtr ret;
5297
5298 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5299 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005300 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005301 return(NULL);
5302 }
5303 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5304 ret->type = XPATH_STRING;
5305 if (val != NULL)
5306 ret->stringval = xmlStrdup(val);
5307 else
5308 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005309#ifdef XP_DEBUG_OBJ_USAGE
5310 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5311#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005312 return(ret);
5313}
5314
5315/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005316 * xmlXPathWrapString:
5317 * @val: the xmlChar * value
5318 *
5319 * Wraps the @val string into an XPath object.
5320 *
5321 * Returns the newly created object.
5322 */
5323xmlXPathObjectPtr
5324xmlXPathWrapString (xmlChar *val) {
5325 xmlXPathObjectPtr ret;
5326
5327 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5328 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005329 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005330 return(NULL);
5331 }
5332 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5333 ret->type = XPATH_STRING;
5334 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005335#ifdef XP_DEBUG_OBJ_USAGE
5336 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5337#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005338 return(ret);
5339}
5340
5341/**
Owen Taylor3473f882001-02-23 17:55:21 +00005342 * xmlXPathNewCString:
5343 * @val: the char * value
5344 *
5345 * Create a new xmlXPathObjectPtr of type string and of value @val
5346 *
5347 * Returns the newly created object.
5348 */
5349xmlXPathObjectPtr
5350xmlXPathNewCString(const char *val) {
5351 xmlXPathObjectPtr ret;
5352
5353 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5354 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005355 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005356 return(NULL);
5357 }
5358 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5359 ret->type = XPATH_STRING;
5360 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005361#ifdef XP_DEBUG_OBJ_USAGE
5362 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5363#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005364 return(ret);
5365}
5366
5367/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005368 * xmlXPathWrapCString:
5369 * @val: the char * value
5370 *
5371 * Wraps a string into an XPath object.
5372 *
5373 * Returns the newly created object.
5374 */
5375xmlXPathObjectPtr
5376xmlXPathWrapCString (char * val) {
5377 return(xmlXPathWrapString((xmlChar *)(val)));
5378}
5379
5380/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005381 * xmlXPathWrapExternal:
5382 * @val: the user data
5383 *
5384 * Wraps the @val data into an XPath object.
5385 *
5386 * Returns the newly created object.
5387 */
5388xmlXPathObjectPtr
5389xmlXPathWrapExternal (void *val) {
5390 xmlXPathObjectPtr ret;
5391
5392 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5393 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005394 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005395 return(NULL);
5396 }
5397 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5398 ret->type = XPATH_USERS;
5399 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005400#ifdef XP_DEBUG_OBJ_USAGE
5401 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5402#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005403 return(ret);
5404}
5405
5406/**
Owen Taylor3473f882001-02-23 17:55:21 +00005407 * xmlXPathObjectCopy:
5408 * @val: the original object
5409 *
5410 * allocate a new copy of a given object
5411 *
5412 * Returns the newly created object.
5413 */
5414xmlXPathObjectPtr
5415xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5416 xmlXPathObjectPtr ret;
5417
5418 if (val == NULL)
5419 return(NULL);
5420
5421 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5422 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005423 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005424 return(NULL);
5425 }
5426 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005427#ifdef XP_DEBUG_OBJ_USAGE
5428 xmlXPathDebugObjUsageRequested(NULL, val->type);
5429#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005430 switch (val->type) {
5431 case XPATH_BOOLEAN:
5432 case XPATH_NUMBER:
5433 case XPATH_POINT:
5434 case XPATH_RANGE:
5435 break;
5436 case XPATH_STRING:
5437 ret->stringval = xmlStrdup(val->stringval);
5438 break;
5439 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005440#if 0
5441/*
5442 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5443 this previous handling is no longer correct, and can cause some serious
5444 problems (ref. bug 145547)
5445*/
Owen Taylor3473f882001-02-23 17:55:21 +00005446 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005447 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005448 xmlNodePtr cur, tmp;
5449 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005450
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005451 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005452 top = xmlNewDoc(NULL);
5453 top->name = (char *)
5454 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005455 ret->user = top;
5456 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005457 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005458 cur = val->nodesetval->nodeTab[0]->children;
5459 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005460 tmp = xmlDocCopyNode(cur, top, 1);
5461 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005462 cur = cur->next;
5463 }
5464 }
William M. Bracke9449c52004-07-11 14:41:20 +00005465
Daniel Veillard9adc0462003-03-24 18:39:54 +00005466 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005467 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005468 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005469 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005470 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005471#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005472 case XPATH_NODESET:
5473 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005474 /* Do not deallocate the copied tree value */
5475 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005476 break;
5477 case XPATH_LOCATIONSET:
5478#ifdef LIBXML_XPTR_ENABLED
5479 {
5480 xmlLocationSetPtr loc = val->user;
5481 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5482 break;
5483 }
5484#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005485 case XPATH_USERS:
5486 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005487 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005488 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005489 xmlGenericError(xmlGenericErrorContext,
5490 "xmlXPathObjectCopy: unsupported type %d\n",
5491 val->type);
5492 break;
5493 }
5494 return(ret);
5495}
5496
5497/**
5498 * xmlXPathFreeObject:
5499 * @obj: the object to free
5500 *
5501 * Free up an xmlXPathObjectPtr object.
5502 */
5503void
5504xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5505 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005506 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005507 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005508#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005509 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005510 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005511 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005512 } else
5513#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005514 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005515 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005516 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005517 } else {
5518 if (obj->nodesetval != NULL)
5519 xmlXPathFreeNodeSet(obj->nodesetval);
5520 }
Owen Taylor3473f882001-02-23 17:55:21 +00005521#ifdef LIBXML_XPTR_ENABLED
5522 } else if (obj->type == XPATH_LOCATIONSET) {
5523 if (obj->user != NULL)
5524 xmlXPtrFreeLocationSet(obj->user);
5525#endif
5526 } else if (obj->type == XPATH_STRING) {
5527 if (obj->stringval != NULL)
5528 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005529 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005530#ifdef XP_DEBUG_OBJ_USAGE
5531 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5532#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005533 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005534}
Owen Taylor3473f882001-02-23 17:55:21 +00005535
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005536/**
5537 * xmlXPathReleaseObject:
5538 * @obj: the xmlXPathObjectPtr to free or to cache
5539 *
5540 * Depending on the state of the cache this frees the given
5541 * XPath object or stores it in the cache.
5542 */
5543static void
5544xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5545{
5546#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5547 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5548 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5549
5550#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5551
5552 if (obj == NULL)
5553 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005554 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005555 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005556 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005557 xmlXPathContextCachePtr cache =
5558 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005559
5560 switch (obj->type) {
5561 case XPATH_NODESET:
5562 case XPATH_XSLT_TREE:
5563 if (obj->nodesetval != NULL) {
5564 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005565 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005566 * It looks like the @boolval is used for
5567 * evaluation if this an XSLT Result Tree Fragment.
5568 * TODO: Check if this assumption is correct.
5569 */
5570 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5571 xmlXPathFreeValueTree(obj->nodesetval);
5572 obj->nodesetval = NULL;
5573 } else if ((obj->nodesetval->nodeMax <= 40) &&
5574 (XP_CACHE_WANTS(cache->nodesetObjs,
5575 cache->maxNodeset)))
5576 {
5577 XP_CACHE_ADD(cache->nodesetObjs, obj);
5578 goto obj_cached;
5579 } else {
5580 xmlXPathFreeNodeSet(obj->nodesetval);
5581 obj->nodesetval = NULL;
5582 }
5583 }
5584 break;
5585 case XPATH_STRING:
5586 if (obj->stringval != NULL)
5587 xmlFree(obj->stringval);
5588
5589 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5590 XP_CACHE_ADD(cache->stringObjs, obj);
5591 goto obj_cached;
5592 }
5593 break;
5594 case XPATH_BOOLEAN:
5595 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5596 XP_CACHE_ADD(cache->booleanObjs, obj);
5597 goto obj_cached;
5598 }
5599 break;
5600 case XPATH_NUMBER:
5601 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5602 XP_CACHE_ADD(cache->numberObjs, obj);
5603 goto obj_cached;
5604 }
5605 break;
5606#ifdef LIBXML_XPTR_ENABLED
5607 case XPATH_LOCATIONSET:
5608 if (obj->user != NULL) {
5609 xmlXPtrFreeLocationSet(obj->user);
5610 }
5611 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005612#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005613 default:
5614 goto free_obj;
5615 }
5616
5617 /*
5618 * Fallback to adding to the misc-objects slot.
5619 */
5620 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5621 XP_CACHE_ADD(cache->miscObjs, obj);
5622 } else
5623 goto free_obj;
5624
5625obj_cached:
5626
5627#ifdef XP_DEBUG_OBJ_USAGE
5628 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5629#endif
5630
5631 if (obj->nodesetval != NULL) {
5632 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005633
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005634 /*
5635 * TODO: Due to those nasty ns-nodes, we need to traverse
5636 * the list and free the ns-nodes.
5637 * URGENT TODO: Check if it's actually slowing things down.
5638 * Maybe we shouldn't try to preserve the list.
5639 */
5640 if (tmpset->nodeNr > 1) {
5641 int i;
5642 xmlNodePtr node;
5643
5644 for (i = 0; i < tmpset->nodeNr; i++) {
5645 node = tmpset->nodeTab[i];
5646 if ((node != NULL) &&
5647 (node->type == XML_NAMESPACE_DECL))
5648 {
5649 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5650 }
5651 }
5652 } else if (tmpset->nodeNr == 1) {
5653 if ((tmpset->nodeTab[0] != NULL) &&
5654 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5655 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005656 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005657 tmpset->nodeNr = 0;
5658 memset(obj, 0, sizeof(xmlXPathObject));
5659 obj->nodesetval = tmpset;
5660 } else
5661 memset(obj, 0, sizeof(xmlXPathObject));
5662
5663 return;
5664
5665free_obj:
5666 /*
5667 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005668 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005669 if (obj->nodesetval != NULL)
5670 xmlXPathFreeNodeSet(obj->nodesetval);
5671#ifdef XP_DEBUG_OBJ_USAGE
5672 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5673#endif
5674 xmlFree(obj);
5675 }
5676 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005677}
5678
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005679
5680/************************************************************************
5681 * *
5682 * Type Casting Routines *
5683 * *
5684 ************************************************************************/
5685
5686/**
5687 * xmlXPathCastBooleanToString:
5688 * @val: a boolean
5689 *
5690 * Converts a boolean to its string value.
5691 *
5692 * Returns a newly allocated string.
5693 */
5694xmlChar *
5695xmlXPathCastBooleanToString (int val) {
5696 xmlChar *ret;
5697 if (val)
5698 ret = xmlStrdup((const xmlChar *) "true");
5699 else
5700 ret = xmlStrdup((const xmlChar *) "false");
5701 return(ret);
5702}
5703
5704/**
5705 * xmlXPathCastNumberToString:
5706 * @val: a number
5707 *
5708 * Converts a number to its string value.
5709 *
5710 * Returns a newly allocated string.
5711 */
5712xmlChar *
5713xmlXPathCastNumberToString (double val) {
5714 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005715 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005716 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005717 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005718 break;
5719 case -1:
5720 ret = xmlStrdup((const xmlChar *) "-Infinity");
5721 break;
5722 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005723 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005724 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005725 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5726 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005727 } else {
5728 /* could be improved */
5729 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005730 xmlXPathFormatNumber(val, buf, 99);
5731 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005732 ret = xmlStrdup((const xmlChar *) buf);
5733 }
5734 }
5735 return(ret);
5736}
5737
5738/**
5739 * xmlXPathCastNodeToString:
5740 * @node: a node
5741 *
5742 * Converts a node to its string value.
5743 *
5744 * Returns a newly allocated string.
5745 */
5746xmlChar *
5747xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005748xmlChar *ret;
5749 if ((ret = xmlNodeGetContent(node)) == NULL)
5750 ret = xmlStrdup((const xmlChar *) "");
5751 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005752}
5753
5754/**
5755 * xmlXPathCastNodeSetToString:
5756 * @ns: a node-set
5757 *
5758 * Converts a node-set to its string value.
5759 *
5760 * Returns a newly allocated string.
5761 */
5762xmlChar *
5763xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5764 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5765 return(xmlStrdup((const xmlChar *) ""));
5766
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005767 if (ns->nodeNr > 1)
5768 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005769 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5770}
5771
5772/**
5773 * xmlXPathCastToString:
5774 * @val: an XPath object
5775 *
5776 * Converts an existing object to its string() equivalent
5777 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005778 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005779 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005780 */
5781xmlChar *
5782xmlXPathCastToString(xmlXPathObjectPtr val) {
5783 xmlChar *ret = NULL;
5784
5785 if (val == NULL)
5786 return(xmlStrdup((const xmlChar *) ""));
5787 switch (val->type) {
5788 case XPATH_UNDEFINED:
5789#ifdef DEBUG_EXPR
5790 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5791#endif
5792 ret = xmlStrdup((const xmlChar *) "");
5793 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005794 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005795 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005796 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5797 break;
5798 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005799 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005800 case XPATH_BOOLEAN:
5801 ret = xmlXPathCastBooleanToString(val->boolval);
5802 break;
5803 case XPATH_NUMBER: {
5804 ret = xmlXPathCastNumberToString(val->floatval);
5805 break;
5806 }
5807 case XPATH_USERS:
5808 case XPATH_POINT:
5809 case XPATH_RANGE:
5810 case XPATH_LOCATIONSET:
5811 TODO
5812 ret = xmlStrdup((const xmlChar *) "");
5813 break;
5814 }
5815 return(ret);
5816}
5817
5818/**
5819 * xmlXPathConvertString:
5820 * @val: an XPath object
5821 *
5822 * Converts an existing object to its string() equivalent
5823 *
5824 * Returns the new object, the old one is freed (or the operation
5825 * is done directly on @val)
5826 */
5827xmlXPathObjectPtr
5828xmlXPathConvertString(xmlXPathObjectPtr val) {
5829 xmlChar *res = NULL;
5830
5831 if (val == NULL)
5832 return(xmlXPathNewCString(""));
5833
5834 switch (val->type) {
5835 case XPATH_UNDEFINED:
5836#ifdef DEBUG_EXPR
5837 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5838#endif
5839 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005840 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005841 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005842 res = xmlXPathCastNodeSetToString(val->nodesetval);
5843 break;
5844 case XPATH_STRING:
5845 return(val);
5846 case XPATH_BOOLEAN:
5847 res = xmlXPathCastBooleanToString(val->boolval);
5848 break;
5849 case XPATH_NUMBER:
5850 res = xmlXPathCastNumberToString(val->floatval);
5851 break;
5852 case XPATH_USERS:
5853 case XPATH_POINT:
5854 case XPATH_RANGE:
5855 case XPATH_LOCATIONSET:
5856 TODO;
5857 break;
5858 }
5859 xmlXPathFreeObject(val);
5860 if (res == NULL)
5861 return(xmlXPathNewCString(""));
5862 return(xmlXPathWrapString(res));
5863}
5864
5865/**
5866 * xmlXPathCastBooleanToNumber:
5867 * @val: a boolean
5868 *
5869 * Converts a boolean to its number value
5870 *
5871 * Returns the number value
5872 */
5873double
5874xmlXPathCastBooleanToNumber(int val) {
5875 if (val)
5876 return(1.0);
5877 return(0.0);
5878}
5879
5880/**
5881 * xmlXPathCastStringToNumber:
5882 * @val: a string
5883 *
5884 * Converts a string to its number value
5885 *
5886 * Returns the number value
5887 */
5888double
5889xmlXPathCastStringToNumber(const xmlChar * val) {
5890 return(xmlXPathStringEvalNumber(val));
5891}
5892
5893/**
5894 * xmlXPathCastNodeToNumber:
5895 * @node: a node
5896 *
5897 * Converts a node to its number value
5898 *
5899 * Returns the number value
5900 */
5901double
5902xmlXPathCastNodeToNumber (xmlNodePtr node) {
5903 xmlChar *strval;
5904 double ret;
5905
5906 if (node == NULL)
5907 return(xmlXPathNAN);
5908 strval = xmlXPathCastNodeToString(node);
5909 if (strval == NULL)
5910 return(xmlXPathNAN);
5911 ret = xmlXPathCastStringToNumber(strval);
5912 xmlFree(strval);
5913
5914 return(ret);
5915}
5916
5917/**
5918 * xmlXPathCastNodeSetToNumber:
5919 * @ns: a node-set
5920 *
5921 * Converts a node-set to its number value
5922 *
5923 * Returns the number value
5924 */
5925double
5926xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5927 xmlChar *str;
5928 double ret;
5929
5930 if (ns == NULL)
5931 return(xmlXPathNAN);
5932 str = xmlXPathCastNodeSetToString(ns);
5933 ret = xmlXPathCastStringToNumber(str);
5934 xmlFree(str);
5935 return(ret);
5936}
5937
5938/**
5939 * xmlXPathCastToNumber:
5940 * @val: an XPath object
5941 *
5942 * Converts an XPath object to its number value
5943 *
5944 * Returns the number value
5945 */
5946double
5947xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5948 double ret = 0.0;
5949
5950 if (val == NULL)
5951 return(xmlXPathNAN);
5952 switch (val->type) {
5953 case XPATH_UNDEFINED:
5954#ifdef DEGUB_EXPR
5955 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5956#endif
5957 ret = xmlXPathNAN;
5958 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005959 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005960 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005961 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5962 break;
5963 case XPATH_STRING:
5964 ret = xmlXPathCastStringToNumber(val->stringval);
5965 break;
5966 case XPATH_NUMBER:
5967 ret = val->floatval;
5968 break;
5969 case XPATH_BOOLEAN:
5970 ret = xmlXPathCastBooleanToNumber(val->boolval);
5971 break;
5972 case XPATH_USERS:
5973 case XPATH_POINT:
5974 case XPATH_RANGE:
5975 case XPATH_LOCATIONSET:
5976 TODO;
5977 ret = xmlXPathNAN;
5978 break;
5979 }
5980 return(ret);
5981}
5982
5983/**
5984 * xmlXPathConvertNumber:
5985 * @val: an XPath object
5986 *
5987 * Converts an existing object to its number() equivalent
5988 *
5989 * Returns the new object, the old one is freed (or the operation
5990 * is done directly on @val)
5991 */
5992xmlXPathObjectPtr
5993xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5994 xmlXPathObjectPtr ret;
5995
5996 if (val == NULL)
5997 return(xmlXPathNewFloat(0.0));
5998 if (val->type == XPATH_NUMBER)
5999 return(val);
6000 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
6001 xmlXPathFreeObject(val);
6002 return(ret);
6003}
6004
6005/**
6006 * xmlXPathCastNumberToBoolean:
6007 * @val: a number
6008 *
6009 * Converts a number to its boolean value
6010 *
6011 * Returns the boolean value
6012 */
6013int
6014xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00006015 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006016 return(0);
6017 return(1);
6018}
6019
6020/**
6021 * xmlXPathCastStringToBoolean:
6022 * @val: a string
6023 *
6024 * Converts a string to its boolean value
6025 *
6026 * Returns the boolean value
6027 */
6028int
6029xmlXPathCastStringToBoolean (const xmlChar *val) {
6030 if ((val == NULL) || (xmlStrlen(val) == 0))
6031 return(0);
6032 return(1);
6033}
6034
6035/**
6036 * xmlXPathCastNodeSetToBoolean:
6037 * @ns: a node-set
6038 *
6039 * Converts a node-set to its boolean value
6040 *
6041 * Returns the boolean value
6042 */
6043int
6044xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6045 if ((ns == NULL) || (ns->nodeNr == 0))
6046 return(0);
6047 return(1);
6048}
6049
6050/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006051 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006052 * @val: an XPath object
6053 *
6054 * Converts an XPath object to its boolean value
6055 *
6056 * Returns the boolean value
6057 */
6058int
6059xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6060 int ret = 0;
6061
6062 if (val == NULL)
6063 return(0);
6064 switch (val->type) {
6065 case XPATH_UNDEFINED:
6066#ifdef DEBUG_EXPR
6067 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6068#endif
6069 ret = 0;
6070 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006071 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00006072 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006073 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6074 break;
6075 case XPATH_STRING:
6076 ret = xmlXPathCastStringToBoolean(val->stringval);
6077 break;
6078 case XPATH_NUMBER:
6079 ret = xmlXPathCastNumberToBoolean(val->floatval);
6080 break;
6081 case XPATH_BOOLEAN:
6082 ret = val->boolval;
6083 break;
6084 case XPATH_USERS:
6085 case XPATH_POINT:
6086 case XPATH_RANGE:
6087 case XPATH_LOCATIONSET:
6088 TODO;
6089 ret = 0;
6090 break;
6091 }
6092 return(ret);
6093}
6094
6095
6096/**
6097 * xmlXPathConvertBoolean:
6098 * @val: an XPath object
6099 *
6100 * Converts an existing object to its boolean() equivalent
6101 *
6102 * Returns the new object, the old one is freed (or the operation
6103 * is done directly on @val)
6104 */
6105xmlXPathObjectPtr
6106xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6107 xmlXPathObjectPtr ret;
6108
6109 if (val == NULL)
6110 return(xmlXPathNewBoolean(0));
6111 if (val->type == XPATH_BOOLEAN)
6112 return(val);
6113 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6114 xmlXPathFreeObject(val);
6115 return(ret);
6116}
6117
Owen Taylor3473f882001-02-23 17:55:21 +00006118/************************************************************************
6119 * *
6120 * Routines to handle XPath contexts *
6121 * *
6122 ************************************************************************/
6123
6124/**
6125 * xmlXPathNewContext:
6126 * @doc: the XML document
6127 *
6128 * Create a new xmlXPathContext
6129 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006130 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006131 */
6132xmlXPathContextPtr
6133xmlXPathNewContext(xmlDocPtr doc) {
6134 xmlXPathContextPtr ret;
6135
6136 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6137 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006138 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006139 return(NULL);
6140 }
6141 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6142 ret->doc = doc;
6143 ret->node = NULL;
6144
6145 ret->varHash = NULL;
6146
6147 ret->nb_types = 0;
6148 ret->max_types = 0;
6149 ret->types = NULL;
6150
6151 ret->funcHash = xmlHashCreate(0);
6152
6153 ret->nb_axis = 0;
6154 ret->max_axis = 0;
6155 ret->axis = NULL;
6156
6157 ret->nsHash = NULL;
6158 ret->user = NULL;
6159
6160 ret->contextSize = -1;
6161 ret->proximityPosition = -1;
6162
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006163#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006164 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006165 xmlXPathFreeContext(ret);
6166 return(NULL);
6167 }
6168#endif
6169
Daniel Veillard45490ae2008-07-29 09:13:19 +00006170 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006171
Owen Taylor3473f882001-02-23 17:55:21 +00006172 return(ret);
6173}
6174
6175/**
6176 * xmlXPathFreeContext:
6177 * @ctxt: the context to free
6178 *
6179 * Free up an xmlXPathContext
6180 */
6181void
6182xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006183 if (ctxt == NULL) return;
6184
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006185 if (ctxt->cache != NULL)
6186 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006187 xmlXPathRegisteredNsCleanup(ctxt);
6188 xmlXPathRegisteredFuncsCleanup(ctxt);
6189 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006190 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006191 xmlFree(ctxt);
6192}
6193
6194/************************************************************************
6195 * *
6196 * Routines to handle XPath parser contexts *
6197 * *
6198 ************************************************************************/
6199
6200#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006201 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006202 __xmlRaiseError(NULL, NULL, NULL, \
6203 NULL, NULL, XML_FROM_XPATH, \
6204 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6205 __FILE__, __LINE__, \
6206 NULL, NULL, NULL, 0, 0, \
6207 "NULL context pointer\n"); \
6208 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006209 } \
6210
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006211#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006212 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006213 __xmlRaiseError(NULL, NULL, NULL, \
6214 NULL, NULL, XML_FROM_XPATH, \
6215 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6216 __FILE__, __LINE__, \
6217 NULL, NULL, NULL, 0, 0, \
6218 "NULL context pointer\n"); \
6219 return(-1); \
6220 } \
6221
Owen Taylor3473f882001-02-23 17:55:21 +00006222
6223#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006224 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006225 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006226 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006227 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006228 }
Owen Taylor3473f882001-02-23 17:55:21 +00006229
6230
6231/**
6232 * xmlXPathNewParserContext:
6233 * @str: the XPath expression
6234 * @ctxt: the XPath context
6235 *
6236 * Create a new xmlXPathParserContext
6237 *
6238 * Returns the xmlXPathParserContext just allocated.
6239 */
6240xmlXPathParserContextPtr
6241xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6242 xmlXPathParserContextPtr ret;
6243
6244 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6245 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006246 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006247 return(NULL);
6248 }
6249 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6250 ret->cur = ret->base = str;
6251 ret->context = ctxt;
6252
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006253 ret->comp = xmlXPathNewCompExpr();
6254 if (ret->comp == NULL) {
6255 xmlFree(ret->valueTab);
6256 xmlFree(ret);
6257 return(NULL);
6258 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006259 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6260 ret->comp->dict = ctxt->dict;
6261 xmlDictReference(ret->comp->dict);
6262 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006263
6264 return(ret);
6265}
6266
6267/**
6268 * xmlXPathCompParserContext:
6269 * @comp: the XPath compiled expression
6270 * @ctxt: the XPath context
6271 *
6272 * Create a new xmlXPathParserContext when processing a compiled expression
6273 *
6274 * Returns the xmlXPathParserContext just allocated.
6275 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006276static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006277xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6278 xmlXPathParserContextPtr ret;
6279
6280 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6281 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006282 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006283 return(NULL);
6284 }
6285 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6286
Owen Taylor3473f882001-02-23 17:55:21 +00006287 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006288 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006289 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006290 if (ret->valueTab == NULL) {
6291 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006292 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006293 return(NULL);
6294 }
Owen Taylor3473f882001-02-23 17:55:21 +00006295 ret->valueNr = 0;
6296 ret->valueMax = 10;
6297 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006298 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006299
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006300 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006301 ret->comp = comp;
6302
Owen Taylor3473f882001-02-23 17:55:21 +00006303 return(ret);
6304}
6305
6306/**
6307 * xmlXPathFreeParserContext:
6308 * @ctxt: the context to free
6309 *
6310 * Free up an xmlXPathParserContext
6311 */
6312void
6313xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006314 int i;
6315
Owen Taylor3473f882001-02-23 17:55:21 +00006316 if (ctxt->valueTab != NULL) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006317 for (i = 0; i < ctxt->valueNr; i++) {
6318 if (ctxt->context)
6319 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6320 else
6321 xmlXPathFreeObject(ctxt->valueTab[i]);
6322 }
Owen Taylor3473f882001-02-23 17:55:21 +00006323 xmlFree(ctxt->valueTab);
6324 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006325 if (ctxt->comp != NULL) {
6326#ifdef XPATH_STREAMING
6327 if (ctxt->comp->stream != NULL) {
6328 xmlFreePatternList(ctxt->comp->stream);
6329 ctxt->comp->stream = NULL;
6330 }
6331#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006332 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006333 }
Owen Taylor3473f882001-02-23 17:55:21 +00006334 xmlFree(ctxt);
6335}
6336
6337/************************************************************************
6338 * *
6339 * The implicit core function library *
6340 * *
6341 ************************************************************************/
6342
Owen Taylor3473f882001-02-23 17:55:21 +00006343/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006344 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006345 * @node: a node pointer
6346 *
6347 * Function computing the beginning of the string value of the node,
6348 * used to speed up comparisons
6349 *
6350 * Returns an int usable as a hash
6351 */
6352static unsigned int
6353xmlXPathNodeValHash(xmlNodePtr node) {
6354 int len = 2;
6355 const xmlChar * string = NULL;
6356 xmlNodePtr tmp = NULL;
6357 unsigned int ret = 0;
6358
6359 if (node == NULL)
6360 return(0);
6361
Daniel Veillard9adc0462003-03-24 18:39:54 +00006362 if (node->type == XML_DOCUMENT_NODE) {
6363 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6364 if (tmp == NULL)
6365 node = node->children;
6366 else
6367 node = tmp;
6368
6369 if (node == NULL)
6370 return(0);
6371 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006372
6373 switch (node->type) {
6374 case XML_COMMENT_NODE:
6375 case XML_PI_NODE:
6376 case XML_CDATA_SECTION_NODE:
6377 case XML_TEXT_NODE:
6378 string = node->content;
6379 if (string == NULL)
6380 return(0);
6381 if (string[0] == 0)
6382 return(0);
6383 return(((unsigned int) string[0]) +
6384 (((unsigned int) string[1]) << 8));
6385 case XML_NAMESPACE_DECL:
6386 string = ((xmlNsPtr)node)->href;
6387 if (string == NULL)
6388 return(0);
6389 if (string[0] == 0)
6390 return(0);
6391 return(((unsigned int) string[0]) +
6392 (((unsigned int) string[1]) << 8));
6393 case XML_ATTRIBUTE_NODE:
6394 tmp = ((xmlAttrPtr) node)->children;
6395 break;
6396 case XML_ELEMENT_NODE:
6397 tmp = node->children;
6398 break;
6399 default:
6400 return(0);
6401 }
6402 while (tmp != NULL) {
6403 switch (tmp->type) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006404 case XML_CDATA_SECTION_NODE:
6405 case XML_TEXT_NODE:
6406 string = tmp->content;
6407 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006408 default:
Nick Wellnhofer5af594d2017-10-07 14:54:45 +02006409 string = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006410 break;
6411 }
6412 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006413 if (len == 1) {
6414 return(ret + (((unsigned int) string[0]) << 8));
6415 }
6416 if (string[1] == 0) {
6417 len = 1;
6418 ret = (unsigned int) string[0];
6419 } else {
6420 return(((unsigned int) string[0]) +
6421 (((unsigned int) string[1]) << 8));
6422 }
6423 }
6424 /*
6425 * Skip to next node
6426 */
6427 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6428 if (tmp->children->type != XML_ENTITY_DECL) {
6429 tmp = tmp->children;
6430 continue;
6431 }
6432 }
6433 if (tmp == node)
6434 break;
6435
6436 if (tmp->next != NULL) {
6437 tmp = tmp->next;
6438 continue;
6439 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006440
Daniel Veillardf06307e2001-07-03 10:35:50 +00006441 do {
6442 tmp = tmp->parent;
6443 if (tmp == NULL)
6444 break;
6445 if (tmp == node) {
6446 tmp = NULL;
6447 break;
6448 }
6449 if (tmp->next != NULL) {
6450 tmp = tmp->next;
6451 break;
6452 }
6453 } while (tmp != NULL);
6454 }
6455 return(ret);
6456}
6457
6458/**
6459 * xmlXPathStringHash:
6460 * @string: a string
6461 *
6462 * Function computing the beginning of the string value of the node,
6463 * used to speed up comparisons
6464 *
6465 * Returns an int usable as a hash
6466 */
6467static unsigned int
6468xmlXPathStringHash(const xmlChar * string) {
6469 if (string == NULL)
6470 return((unsigned int) 0);
6471 if (string[0] == 0)
6472 return(0);
6473 return(((unsigned int) string[0]) +
6474 (((unsigned int) string[1]) << 8));
6475}
6476
6477/**
Owen Taylor3473f882001-02-23 17:55:21 +00006478 * xmlXPathCompareNodeSetFloat:
6479 * @ctxt: the XPath Parser context
6480 * @inf: less than (1) or greater than (0)
6481 * @strict: is the comparison strict
6482 * @arg: the node set
6483 * @f: the value
6484 *
6485 * Implement the compare operation between a nodeset and a number
6486 * @ns < @val (1, 1, ...
6487 * @ns <= @val (1, 0, ...
6488 * @ns > @val (0, 1, ...
6489 * @ns >= @val (0, 0, ...
6490 *
6491 * If one object to be compared is a node-set and the other is a number,
6492 * then the comparison will be true if and only if there is a node in the
6493 * node-set such that the result of performing the comparison on the number
6494 * to be compared and on the result of converting the string-value of that
6495 * node to a number using the number function is true.
6496 *
6497 * Returns 0 or 1 depending on the results of the test.
6498 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006499static int
Owen Taylor3473f882001-02-23 17:55:21 +00006500xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6501 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6502 int i, ret = 0;
6503 xmlNodeSetPtr ns;
6504 xmlChar *str2;
6505
6506 if ((f == NULL) || (arg == NULL) ||
6507 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006508 xmlXPathReleaseObject(ctxt->context, arg);
6509 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006510 return(0);
6511 }
6512 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006513 if (ns != NULL) {
6514 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006515 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006516 if (str2 != NULL) {
6517 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006518 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006519 xmlFree(str2);
6520 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006521 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006522 ret = xmlXPathCompareValues(ctxt, inf, strict);
6523 if (ret)
6524 break;
6525 }
6526 }
Owen Taylor3473f882001-02-23 17:55:21 +00006527 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006528 xmlXPathReleaseObject(ctxt->context, arg);
6529 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006530 return(ret);
6531}
6532
6533/**
6534 * xmlXPathCompareNodeSetString:
6535 * @ctxt: the XPath Parser context
6536 * @inf: less than (1) or greater than (0)
6537 * @strict: is the comparison strict
6538 * @arg: the node set
6539 * @s: the value
6540 *
6541 * Implement the compare operation between a nodeset and a string
6542 * @ns < @val (1, 1, ...
6543 * @ns <= @val (1, 0, ...
6544 * @ns > @val (0, 1, ...
6545 * @ns >= @val (0, 0, ...
6546 *
6547 * If one object to be compared is a node-set and the other is a string,
6548 * then the comparison will be true if and only if there is a node in
6549 * the node-set such that the result of performing the comparison on the
6550 * string-value of the node and the other string is true.
6551 *
6552 * Returns 0 or 1 depending on the results of the test.
6553 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006554static int
Owen Taylor3473f882001-02-23 17:55:21 +00006555xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6556 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6557 int i, ret = 0;
6558 xmlNodeSetPtr ns;
6559 xmlChar *str2;
6560
6561 if ((s == NULL) || (arg == NULL) ||
6562 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006563 xmlXPathReleaseObject(ctxt->context, arg);
6564 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006565 return(0);
6566 }
6567 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006568 if (ns != NULL) {
6569 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006570 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006571 if (str2 != NULL) {
6572 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006573 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006574 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006575 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006576 ret = xmlXPathCompareValues(ctxt, inf, strict);
6577 if (ret)
6578 break;
6579 }
6580 }
Owen Taylor3473f882001-02-23 17:55:21 +00006581 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006582 xmlXPathReleaseObject(ctxt->context, arg);
6583 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006584 return(ret);
6585}
6586
6587/**
6588 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006589 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006590 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006591 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006592 * @arg2: the second node set object
6593 *
6594 * Implement the compare operation on nodesets:
6595 *
6596 * If both objects to be compared are node-sets, then the comparison
6597 * will be true if and only if there is a node in the first node-set
6598 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006599 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006600 * ....
6601 * When neither object to be compared is a node-set and the operator
6602 * is <=, <, >= or >, then the objects are compared by converting both
6603 * objects to numbers and comparing the numbers according to IEEE 754.
6604 * ....
6605 * The number function converts its argument to a number as follows:
6606 * - a string that consists of optional whitespace followed by an
6607 * optional minus sign followed by a Number followed by whitespace
6608 * is converted to the IEEE 754 number that is nearest (according
6609 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6610 * represented by the string; any other string is converted to NaN
6611 *
6612 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006613 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006614 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006615static int
6616xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006617 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6618 int i, j, init = 0;
6619 double val1;
6620 double *values2;
6621 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006622 xmlNodeSetPtr ns1;
6623 xmlNodeSetPtr ns2;
6624
6625 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006626 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6627 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006628 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006629 }
Owen Taylor3473f882001-02-23 17:55:21 +00006630 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006631 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6632 xmlXPathFreeObject(arg1);
6633 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006634 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006635 }
Owen Taylor3473f882001-02-23 17:55:21 +00006636
6637 ns1 = arg1->nodesetval;
6638 ns2 = arg2->nodesetval;
6639
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006640 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006641 xmlXPathFreeObject(arg1);
6642 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006643 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006644 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006645 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006646 xmlXPathFreeObject(arg1);
6647 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006648 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006649 }
Owen Taylor3473f882001-02-23 17:55:21 +00006650
6651 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6652 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006653 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006654 xmlXPathFreeObject(arg1);
6655 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006656 return(0);
6657 }
6658 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006659 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006660 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006661 continue;
6662 for (j = 0;j < ns2->nodeNr;j++) {
6663 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006664 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006665 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006666 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006667 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006668 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006669 ret = (val1 < values2[j]);
6670 else if (inf && !strict)
6671 ret = (val1 <= values2[j]);
6672 else if (!inf && strict)
6673 ret = (val1 > values2[j]);
6674 else if (!inf && !strict)
6675 ret = (val1 >= values2[j]);
6676 if (ret)
6677 break;
6678 }
6679 if (ret)
6680 break;
6681 init = 1;
6682 }
6683 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006684 xmlXPathFreeObject(arg1);
6685 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006686 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006687}
6688
6689/**
6690 * xmlXPathCompareNodeSetValue:
6691 * @ctxt: the XPath Parser context
6692 * @inf: less than (1) or greater than (0)
6693 * @strict: is the comparison strict
6694 * @arg: the node set
6695 * @val: the value
6696 *
6697 * Implement the compare operation between a nodeset and a value
6698 * @ns < @val (1, 1, ...
6699 * @ns <= @val (1, 0, ...
6700 * @ns > @val (0, 1, ...
6701 * @ns >= @val (0, 0, ...
6702 *
6703 * If one object to be compared is a node-set and the other is a boolean,
6704 * then the comparison will be true if and only if the result of performing
6705 * the comparison on the boolean and on the result of converting
6706 * the node-set to a boolean using the boolean function is true.
6707 *
6708 * Returns 0 or 1 depending on the results of the test.
6709 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006710static int
Owen Taylor3473f882001-02-23 17:55:21 +00006711xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6712 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6713 if ((val == NULL) || (arg == NULL) ||
6714 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6715 return(0);
6716
6717 switch(val->type) {
6718 case XPATH_NUMBER:
6719 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6720 case XPATH_NODESET:
6721 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006722 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006723 case XPATH_STRING:
6724 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6725 case XPATH_BOOLEAN:
6726 valuePush(ctxt, arg);
6727 xmlXPathBooleanFunction(ctxt, 1);
6728 valuePush(ctxt, val);
6729 return(xmlXPathCompareValues(ctxt, inf, strict));
6730 default:
Nick Wellnhofercf60dbe2017-05-25 16:20:56 +02006731 xmlGenericError(xmlGenericErrorContext,
6732 "xmlXPathCompareNodeSetValue: Can't compare node set "
6733 "and object of type %d\n",
6734 val->type);
6735 xmlXPathReleaseObject(ctxt->context, arg);
6736 xmlXPathReleaseObject(ctxt->context, val);
6737 XP_ERROR0(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006738 }
6739 return(0);
6740}
6741
6742/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006743 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006744 * @arg: the nodeset object argument
6745 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006746 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006747 *
6748 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6749 * If one object to be compared is a node-set and the other is a string,
6750 * then the comparison will be true if and only if there is a node in
6751 * the node-set such that the result of performing the comparison on the
6752 * string-value of the node and the other string is true.
6753 *
6754 * Returns 0 or 1 depending on the results of the test.
6755 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006756static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006757xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006758{
Owen Taylor3473f882001-02-23 17:55:21 +00006759 int i;
6760 xmlNodeSetPtr ns;
6761 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006762 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006763
6764 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006765 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6766 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006767 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006768 /*
6769 * A NULL nodeset compared with a string is always false
6770 * (since there is no node equal, and no node not equal)
6771 */
6772 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006773 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006774 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006775 for (i = 0; i < ns->nodeNr; i++) {
6776 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6777 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6778 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6779 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006780 if (neq)
6781 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006782 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006783 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6784 if (neq)
6785 continue;
6786 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006787 } else if (neq) {
6788 if (str2 != NULL)
6789 xmlFree(str2);
6790 return (1);
6791 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006792 if (str2 != NULL)
6793 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006794 } else if (neq)
6795 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006796 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006797 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006798}
6799
6800/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006801 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006802 * @arg: the nodeset object argument
6803 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006804 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006805 *
6806 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6807 * If one object to be compared is a node-set and the other is a number,
6808 * then the comparison will be true if and only if there is a node in
6809 * the node-set such that the result of performing the comparison on the
6810 * number to be compared and on the result of converting the string-value
6811 * of that node to a number using the number function is true.
6812 *
6813 * Returns 0 or 1 depending on the results of the test.
6814 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006815static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006816xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6817 xmlXPathObjectPtr arg, double f, int neq) {
6818 int i, ret=0;
6819 xmlNodeSetPtr ns;
6820 xmlChar *str2;
6821 xmlXPathObjectPtr val;
6822 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006823
6824 if ((arg == NULL) ||
6825 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6826 return(0);
6827
William M. Brack0c022ad2002-07-12 00:56:01 +00006828 ns = arg->nodesetval;
6829 if (ns != NULL) {
6830 for (i=0;i<ns->nodeNr;i++) {
6831 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6832 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006833 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006834 xmlFree(str2);
6835 xmlXPathNumberFunction(ctxt, 1);
6836 val = valuePop(ctxt);
6837 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006838 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006839 if (!xmlXPathIsNaN(v)) {
6840 if ((!neq) && (v==f)) {
6841 ret = 1;
6842 break;
6843 } else if ((neq) && (v!=f)) {
6844 ret = 1;
6845 break;
6846 }
William M. Brack32f0f712005-07-14 07:00:33 +00006847 } else { /* NaN is unequal to any value */
6848 if (neq)
6849 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006850 }
6851 }
6852 }
6853 }
6854
6855 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006856}
6857
6858
6859/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006860 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006861 * @arg1: first nodeset object argument
6862 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006863 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006864 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006865 * Implement the equal / not equal operation on XPath nodesets:
6866 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006867 * If both objects to be compared are node-sets, then the comparison
6868 * will be true if and only if there is a node in the first node-set and
6869 * a node in the second node-set such that the result of performing the
6870 * comparison on the string-values of the two nodes is true.
6871 *
6872 * (needless to say, this is a costly operation)
6873 *
6874 * Returns 0 or 1 depending on the results of the test.
6875 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006876static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006877xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006878 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006879 unsigned int *hashs1;
6880 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006881 xmlChar **values1;
6882 xmlChar **values2;
6883 int ret = 0;
6884 xmlNodeSetPtr ns1;
6885 xmlNodeSetPtr ns2;
6886
6887 if ((arg1 == NULL) ||
6888 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6889 return(0);
6890 if ((arg2 == NULL) ||
6891 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6892 return(0);
6893
6894 ns1 = arg1->nodesetval;
6895 ns2 = arg2->nodesetval;
6896
Daniel Veillard911f49a2001-04-07 15:39:35 +00006897 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006898 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006899 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006900 return(0);
6901
6902 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006903 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006904 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006905 if (neq == 0)
6906 for (i = 0;i < ns1->nodeNr;i++)
6907 for (j = 0;j < ns2->nodeNr;j++)
6908 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6909 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006910
6911 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006912 if (values1 == NULL) {
6913 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006914 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006915 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006916 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6917 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006918 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006919 xmlFree(values1);
6920 return(0);
6921 }
Owen Taylor3473f882001-02-23 17:55:21 +00006922 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6923 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6924 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006925 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006926 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006927 xmlFree(values1);
6928 return(0);
6929 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006930 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6931 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006932 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006933 xmlFree(hashs1);
6934 xmlFree(values1);
6935 xmlFree(values2);
6936 return(0);
6937 }
Owen Taylor3473f882001-02-23 17:55:21 +00006938 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6939 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006940 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006941 for (j = 0;j < ns2->nodeNr;j++) {
6942 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006943 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006944 if (hashs1[i] != hashs2[j]) {
6945 if (neq) {
6946 ret = 1;
6947 break;
6948 }
6949 }
6950 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006951 if (values1[i] == NULL)
6952 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6953 if (values2[j] == NULL)
6954 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006955 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006956 if (ret)
6957 break;
6958 }
Owen Taylor3473f882001-02-23 17:55:21 +00006959 }
6960 if (ret)
6961 break;
6962 }
6963 for (i = 0;i < ns1->nodeNr;i++)
6964 if (values1[i] != NULL)
6965 xmlFree(values1[i]);
6966 for (j = 0;j < ns2->nodeNr;j++)
6967 if (values2[j] != NULL)
6968 xmlFree(values2[j]);
6969 xmlFree(values1);
6970 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006971 xmlFree(hashs1);
6972 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006973 return(ret);
6974}
6975
William M. Brack0c022ad2002-07-12 00:56:01 +00006976static int
6977xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6978 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006979 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006980 /*
6981 *At this point we are assured neither arg1 nor arg2
6982 *is a nodeset, so we can just pick the appropriate routine.
6983 */
Owen Taylor3473f882001-02-23 17:55:21 +00006984 switch (arg1->type) {
6985 case XPATH_UNDEFINED:
6986#ifdef DEBUG_EXPR
6987 xmlGenericError(xmlGenericErrorContext,
6988 "Equal: undefined\n");
6989#endif
6990 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006991 case XPATH_BOOLEAN:
6992 switch (arg2->type) {
6993 case XPATH_UNDEFINED:
6994#ifdef DEBUG_EXPR
6995 xmlGenericError(xmlGenericErrorContext,
6996 "Equal: undefined\n");
6997#endif
6998 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006999 case XPATH_BOOLEAN:
7000#ifdef DEBUG_EXPR
7001 xmlGenericError(xmlGenericErrorContext,
7002 "Equal: %d boolean %d \n",
7003 arg1->boolval, arg2->boolval);
7004#endif
7005 ret = (arg1->boolval == arg2->boolval);
7006 break;
7007 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00007008 ret = (arg1->boolval ==
7009 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007010 break;
7011 case XPATH_STRING:
7012 if ((arg2->stringval == NULL) ||
7013 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007014 else
Owen Taylor3473f882001-02-23 17:55:21 +00007015 ret = 1;
7016 ret = (arg1->boolval == ret);
7017 break;
7018 case XPATH_USERS:
7019 case XPATH_POINT:
7020 case XPATH_RANGE:
7021 case XPATH_LOCATIONSET:
7022 TODO
7023 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007024 case XPATH_NODESET:
7025 case XPATH_XSLT_TREE:
7026 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007027 }
7028 break;
7029 case XPATH_NUMBER:
7030 switch (arg2->type) {
7031 case XPATH_UNDEFINED:
7032#ifdef DEBUG_EXPR
7033 xmlGenericError(xmlGenericErrorContext,
7034 "Equal: undefined\n");
7035#endif
7036 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007037 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00007038 ret = (arg2->boolval==
7039 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007040 break;
7041 case XPATH_STRING:
7042 valuePush(ctxt, arg2);
7043 xmlXPathNumberFunction(ctxt, 1);
7044 arg2 = valuePop(ctxt);
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +02007045 /* Falls through. */
Owen Taylor3473f882001-02-23 17:55:21 +00007046 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007047 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007048 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007049 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007050 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007051 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7052 if (xmlXPathIsInf(arg2->floatval) == 1)
7053 ret = 1;
7054 else
7055 ret = 0;
7056 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7057 if (xmlXPathIsInf(arg2->floatval) == -1)
7058 ret = 1;
7059 else
7060 ret = 0;
7061 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7062 if (xmlXPathIsInf(arg1->floatval) == 1)
7063 ret = 1;
7064 else
7065 ret = 0;
7066 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7067 if (xmlXPathIsInf(arg1->floatval) == -1)
7068 ret = 1;
7069 else
7070 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007071 } else {
7072 ret = (arg1->floatval == arg2->floatval);
7073 }
Owen Taylor3473f882001-02-23 17:55:21 +00007074 break;
7075 case XPATH_USERS:
7076 case XPATH_POINT:
7077 case XPATH_RANGE:
7078 case XPATH_LOCATIONSET:
7079 TODO
7080 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007081 case XPATH_NODESET:
7082 case XPATH_XSLT_TREE:
7083 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007084 }
7085 break;
7086 case XPATH_STRING:
7087 switch (arg2->type) {
7088 case XPATH_UNDEFINED:
7089#ifdef DEBUG_EXPR
7090 xmlGenericError(xmlGenericErrorContext,
7091 "Equal: undefined\n");
7092#endif
7093 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007094 case XPATH_BOOLEAN:
7095 if ((arg1->stringval == NULL) ||
7096 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007097 else
Owen Taylor3473f882001-02-23 17:55:21 +00007098 ret = 1;
7099 ret = (arg2->boolval == ret);
7100 break;
7101 case XPATH_STRING:
7102 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7103 break;
7104 case XPATH_NUMBER:
7105 valuePush(ctxt, arg1);
7106 xmlXPathNumberFunction(ctxt, 1);
7107 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007108 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007109 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007110 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007111 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007112 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7113 if (xmlXPathIsInf(arg2->floatval) == 1)
7114 ret = 1;
7115 else
7116 ret = 0;
7117 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7118 if (xmlXPathIsInf(arg2->floatval) == -1)
7119 ret = 1;
7120 else
7121 ret = 0;
7122 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7123 if (xmlXPathIsInf(arg1->floatval) == 1)
7124 ret = 1;
7125 else
7126 ret = 0;
7127 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7128 if (xmlXPathIsInf(arg1->floatval) == -1)
7129 ret = 1;
7130 else
7131 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007132 } else {
7133 ret = (arg1->floatval == arg2->floatval);
7134 }
Owen Taylor3473f882001-02-23 17:55:21 +00007135 break;
7136 case XPATH_USERS:
7137 case XPATH_POINT:
7138 case XPATH_RANGE:
7139 case XPATH_LOCATIONSET:
7140 TODO
7141 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007142 case XPATH_NODESET:
7143 case XPATH_XSLT_TREE:
7144 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007145 }
7146 break;
7147 case XPATH_USERS:
7148 case XPATH_POINT:
7149 case XPATH_RANGE:
7150 case XPATH_LOCATIONSET:
7151 TODO
7152 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007153 case XPATH_NODESET:
7154 case XPATH_XSLT_TREE:
7155 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007156 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007157 xmlXPathReleaseObject(ctxt->context, arg1);
7158 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007159 return(ret);
7160}
7161
William M. Brack0c022ad2002-07-12 00:56:01 +00007162/**
7163 * xmlXPathEqualValues:
7164 * @ctxt: the XPath Parser context
7165 *
7166 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7167 *
7168 * Returns 0 or 1 depending on the results of the test.
7169 */
7170int
7171xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7172 xmlXPathObjectPtr arg1, arg2, argtmp;
7173 int ret = 0;
7174
Daniel Veillard6128c012004-11-08 17:16:15 +00007175 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007176 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007177 arg1 = valuePop(ctxt);
7178 if ((arg1 == NULL) || (arg2 == NULL)) {
7179 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007180 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007181 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007182 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007183 XP_ERROR0(XPATH_INVALID_OPERAND);
7184 }
7185
7186 if (arg1 == arg2) {
7187#ifdef DEBUG_EXPR
7188 xmlGenericError(xmlGenericErrorContext,
7189 "Equal: by pointer\n");
7190#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007191 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007192 return(1);
7193 }
7194
7195 /*
7196 *If either argument is a nodeset, it's a 'special case'
7197 */
7198 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7199 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7200 /*
7201 *Hack it to assure arg1 is the nodeset
7202 */
7203 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7204 argtmp = arg2;
7205 arg2 = arg1;
7206 arg1 = argtmp;
7207 }
7208 switch (arg2->type) {
7209 case XPATH_UNDEFINED:
7210#ifdef DEBUG_EXPR
7211 xmlGenericError(xmlGenericErrorContext,
7212 "Equal: undefined\n");
7213#endif
7214 break;
7215 case XPATH_NODESET:
7216 case XPATH_XSLT_TREE:
7217 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7218 break;
7219 case XPATH_BOOLEAN:
7220 if ((arg1->nodesetval == NULL) ||
7221 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007222 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007223 ret = 1;
7224 ret = (ret == arg2->boolval);
7225 break;
7226 case XPATH_NUMBER:
7227 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7228 break;
7229 case XPATH_STRING:
7230 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7231 break;
7232 case XPATH_USERS:
7233 case XPATH_POINT:
7234 case XPATH_RANGE:
7235 case XPATH_LOCATIONSET:
7236 TODO
7237 break;
7238 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007239 xmlXPathReleaseObject(ctxt->context, arg1);
7240 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007241 return(ret);
7242 }
7243
7244 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7245}
7246
7247/**
7248 * xmlXPathNotEqualValues:
7249 * @ctxt: the XPath Parser context
7250 *
7251 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7252 *
7253 * Returns 0 or 1 depending on the results of the test.
7254 */
7255int
7256xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7257 xmlXPathObjectPtr arg1, arg2, argtmp;
7258 int ret = 0;
7259
Daniel Veillard6128c012004-11-08 17:16:15 +00007260 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007261 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007262 arg1 = valuePop(ctxt);
7263 if ((arg1 == NULL) || (arg2 == NULL)) {
7264 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007265 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007266 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007267 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007268 XP_ERROR0(XPATH_INVALID_OPERAND);
7269 }
7270
7271 if (arg1 == arg2) {
7272#ifdef DEBUG_EXPR
7273 xmlGenericError(xmlGenericErrorContext,
7274 "NotEqual: by pointer\n");
7275#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007276 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007277 return(0);
7278 }
7279
7280 /*
7281 *If either argument is a nodeset, it's a 'special case'
7282 */
7283 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7284 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7285 /*
7286 *Hack it to assure arg1 is the nodeset
7287 */
7288 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7289 argtmp = arg2;
7290 arg2 = arg1;
7291 arg1 = argtmp;
7292 }
7293 switch (arg2->type) {
7294 case XPATH_UNDEFINED:
7295#ifdef DEBUG_EXPR
7296 xmlGenericError(xmlGenericErrorContext,
7297 "NotEqual: undefined\n");
7298#endif
7299 break;
7300 case XPATH_NODESET:
7301 case XPATH_XSLT_TREE:
7302 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7303 break;
7304 case XPATH_BOOLEAN:
7305 if ((arg1->nodesetval == NULL) ||
7306 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007307 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007308 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007309 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007310 break;
7311 case XPATH_NUMBER:
7312 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7313 break;
7314 case XPATH_STRING:
7315 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7316 break;
7317 case XPATH_USERS:
7318 case XPATH_POINT:
7319 case XPATH_RANGE:
7320 case XPATH_LOCATIONSET:
7321 TODO
7322 break;
7323 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007324 xmlXPathReleaseObject(ctxt->context, arg1);
7325 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007326 return(ret);
7327 }
7328
7329 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7330}
Owen Taylor3473f882001-02-23 17:55:21 +00007331
7332/**
7333 * xmlXPathCompareValues:
7334 * @ctxt: the XPath Parser context
7335 * @inf: less than (1) or greater than (0)
7336 * @strict: is the comparison strict
7337 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007338 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007339 * @arg1 < @arg2 (1, 1, ...
7340 * @arg1 <= @arg2 (1, 0, ...
7341 * @arg1 > @arg2 (0, 1, ...
7342 * @arg1 >= @arg2 (0, 0, ...
7343 *
7344 * When neither object to be compared is a node-set and the operator is
7345 * <=, <, >=, >, then the objects are compared by converted both objects
7346 * to numbers and comparing the numbers according to IEEE 754. The <
7347 * comparison will be true if and only if the first number is less than the
7348 * second number. The <= comparison will be true if and only if the first
7349 * number is less than or equal to the second number. The > comparison
7350 * will be true if and only if the first number is greater than the second
7351 * number. The >= comparison will be true if and only if the first number
7352 * is greater than or equal to the second number.
7353 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007354 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007355 */
7356int
7357xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007358 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007359 xmlXPathObjectPtr arg1, arg2;
7360
Daniel Veillard6128c012004-11-08 17:16:15 +00007361 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007362 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007363 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007364 if ((arg1 == NULL) || (arg2 == NULL)) {
7365 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007366 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007367 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007368 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007369 XP_ERROR0(XPATH_INVALID_OPERAND);
7370 }
7371
William M. Brack0c022ad2002-07-12 00:56:01 +00007372 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7373 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007374 /*
7375 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7376 * are not freed from within this routine; they will be freed from the
7377 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7378 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007379 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7380 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007381 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007382 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007383 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007384 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7385 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007386 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007387 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7388 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007389 }
7390 }
7391 return(ret);
7392 }
7393
7394 if (arg1->type != XPATH_NUMBER) {
7395 valuePush(ctxt, arg1);
7396 xmlXPathNumberFunction(ctxt, 1);
7397 arg1 = valuePop(ctxt);
7398 }
7399 if (arg1->type != XPATH_NUMBER) {
7400 xmlXPathFreeObject(arg1);
7401 xmlXPathFreeObject(arg2);
7402 XP_ERROR0(XPATH_INVALID_OPERAND);
7403 }
7404 if (arg2->type != XPATH_NUMBER) {
7405 valuePush(ctxt, arg2);
7406 xmlXPathNumberFunction(ctxt, 1);
7407 arg2 = valuePop(ctxt);
7408 }
7409 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007410 xmlXPathReleaseObject(ctxt->context, arg1);
7411 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007412 XP_ERROR0(XPATH_INVALID_OPERAND);
7413 }
7414 /*
7415 * Add tests for infinity and nan
7416 * => feedback on 3.4 for Inf and NaN
7417 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007418 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007419 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007420 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007421 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007422 arg1i=xmlXPathIsInf(arg1->floatval);
7423 arg2i=xmlXPathIsInf(arg2->floatval);
7424 if (inf && strict) {
7425 if ((arg1i == -1 && arg2i != -1) ||
7426 (arg2i == 1 && arg1i != 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 ret = 1;
7437 } else if (arg1i == 0 && arg2i == 0) {
7438 ret = (arg1->floatval <= arg2->floatval);
7439 } else {
7440 ret = 0;
7441 }
7442 }
7443 else if (!inf && strict) {
7444 if ((arg1i == 1 && arg2i != 1) ||
7445 (arg2i == -1 && arg1i != -1)) {
7446 ret = 1;
7447 } else if (arg1i == 0 && arg2i == 0) {
7448 ret = (arg1->floatval > arg2->floatval);
7449 } else {
7450 ret = 0;
7451 }
7452 }
7453 else if (!inf && !strict) {
7454 if (arg1i == 1 || arg2i == -1) {
7455 ret = 1;
7456 } else if (arg1i == 0 && arg2i == 0) {
7457 ret = (arg1->floatval >= arg2->floatval);
7458 } else {
7459 ret = 0;
7460 }
7461 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007462 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007463 xmlXPathReleaseObject(ctxt->context, arg1);
7464 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007465 return(ret);
7466}
7467
7468/**
7469 * xmlXPathValueFlipSign:
7470 * @ctxt: the XPath Parser context
7471 *
7472 * Implement the unary - operation on an XPath object
7473 * The numeric operators convert their operands to numbers as if
7474 * by calling the number function.
7475 */
7476void
7477xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007478 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007479 CAST_TO_NUMBER;
7480 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007481 if (xmlXPathIsNaN(ctxt->value->floatval))
7482 ctxt->value->floatval=xmlXPathNAN;
7483 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7484 ctxt->value->floatval=xmlXPathNINF;
7485 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7486 ctxt->value->floatval=xmlXPathPINF;
7487 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007488 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7489 ctxt->value->floatval = xmlXPathNZERO;
7490 else
7491 ctxt->value->floatval = 0;
7492 }
7493 else
7494 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007495}
7496
7497/**
7498 * xmlXPathAddValues:
7499 * @ctxt: the XPath Parser context
7500 *
7501 * Implement the add operation on XPath objects:
7502 * The numeric operators convert their operands to numbers as if
7503 * by calling the number function.
7504 */
7505void
7506xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7507 xmlXPathObjectPtr arg;
7508 double val;
7509
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007510 arg = valuePop(ctxt);
7511 if (arg == NULL)
7512 XP_ERROR(XPATH_INVALID_OPERAND);
7513 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007514 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007515 CAST_TO_NUMBER;
7516 CHECK_TYPE(XPATH_NUMBER);
7517 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007518}
7519
7520/**
7521 * xmlXPathSubValues:
7522 * @ctxt: the XPath Parser context
7523 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007524 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007525 * The numeric operators convert their operands to numbers as if
7526 * by calling the number function.
7527 */
7528void
7529xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7530 xmlXPathObjectPtr arg;
7531 double val;
7532
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007533 arg = valuePop(ctxt);
7534 if (arg == NULL)
7535 XP_ERROR(XPATH_INVALID_OPERAND);
7536 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007537 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007538 CAST_TO_NUMBER;
7539 CHECK_TYPE(XPATH_NUMBER);
7540 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007541}
7542
7543/**
7544 * xmlXPathMultValues:
7545 * @ctxt: the XPath Parser context
7546 *
7547 * Implement the multiply operation on XPath objects:
7548 * The numeric operators convert their operands to numbers as if
7549 * by calling the number function.
7550 */
7551void
7552xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7553 xmlXPathObjectPtr arg;
7554 double val;
7555
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007556 arg = valuePop(ctxt);
7557 if (arg == NULL)
7558 XP_ERROR(XPATH_INVALID_OPERAND);
7559 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007560 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007561 CAST_TO_NUMBER;
7562 CHECK_TYPE(XPATH_NUMBER);
7563 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007564}
7565
7566/**
7567 * xmlXPathDivValues:
7568 * @ctxt: the XPath Parser context
7569 *
7570 * Implement the div operation on XPath objects @arg1 / @arg2:
7571 * The numeric operators convert their operands to numbers as if
7572 * by calling the number function.
7573 */
7574void
7575xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7576 xmlXPathObjectPtr arg;
7577 double val;
7578
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007579 arg = valuePop(ctxt);
7580 if (arg == NULL)
7581 XP_ERROR(XPATH_INVALID_OPERAND);
7582 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007583 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007584 CAST_TO_NUMBER;
7585 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007586 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7587 ctxt->value->floatval = xmlXPathNAN;
7588 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007589 if (ctxt->value->floatval == 0)
7590 ctxt->value->floatval = xmlXPathNAN;
7591 else if (ctxt->value->floatval > 0)
7592 ctxt->value->floatval = xmlXPathNINF;
7593 else if (ctxt->value->floatval < 0)
7594 ctxt->value->floatval = xmlXPathPINF;
7595 }
7596 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007597 if (ctxt->value->floatval == 0)
7598 ctxt->value->floatval = xmlXPathNAN;
7599 else if (ctxt->value->floatval > 0)
7600 ctxt->value->floatval = xmlXPathPINF;
7601 else if (ctxt->value->floatval < 0)
7602 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007603 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007604 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007605}
7606
7607/**
7608 * xmlXPathModValues:
7609 * @ctxt: the XPath Parser context
7610 *
7611 * Implement the mod operation on XPath objects: @arg1 / @arg2
7612 * The numeric operators convert their operands to numbers as if
7613 * by calling the number function.
7614 */
7615void
7616xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7617 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007618 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007619
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007620 arg = valuePop(ctxt);
7621 if (arg == NULL)
7622 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007623 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007624 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007625 CAST_TO_NUMBER;
7626 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007627 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007628 if (arg2 == 0)
7629 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007630 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007631 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007632 }
Owen Taylor3473f882001-02-23 17:55:21 +00007633}
7634
7635/************************************************************************
7636 * *
7637 * The traversal functions *
7638 * *
7639 ************************************************************************/
7640
Owen Taylor3473f882001-02-23 17:55:21 +00007641/*
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 */
7646typedef xmlNodePtr (*xmlXPathTraversalFunction)
7647 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7648
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007649/*
7650 * xmlXPathTraversalFunctionExt:
7651 * A traversal function enumerates nodes along an axis.
7652 * Initially it must be called with NULL, and it indicates
7653 * termination on the axis by returning NULL.
7654 * The context node of the traversal is specified via @contextNode.
7655 */
7656typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7657 (xmlNodePtr cur, xmlNodePtr contextNode);
7658
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007659/*
7660 * xmlXPathNodeSetMergeFunction:
7661 * Used for merging node sets in xmlXPathCollectAndTest().
7662 */
7663typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7664 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7665
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007666
Owen Taylor3473f882001-02-23 17:55:21 +00007667/**
7668 * xmlXPathNextSelf:
7669 * @ctxt: the XPath Parser context
7670 * @cur: the current node in the traversal
7671 *
7672 * Traversal function for the "self" direction
7673 * The self axis contains just the context node itself
7674 *
7675 * Returns the next element following that axis
7676 */
7677xmlNodePtr
7678xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007679 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007680 if (cur == NULL)
7681 return(ctxt->context->node);
7682 return(NULL);
7683}
7684
7685/**
7686 * xmlXPathNextChild:
7687 * @ctxt: the XPath Parser context
7688 * @cur: the current node in the traversal
7689 *
7690 * Traversal function for the "child" direction
7691 * The child axis contains the children of the context node in document order.
7692 *
7693 * Returns the next element following that axis
7694 */
7695xmlNodePtr
7696xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007697 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007698 if (cur == NULL) {
7699 if (ctxt->context->node == NULL) return(NULL);
7700 switch (ctxt->context->node->type) {
7701 case XML_ELEMENT_NODE:
7702 case XML_TEXT_NODE:
7703 case XML_CDATA_SECTION_NODE:
7704 case XML_ENTITY_REF_NODE:
7705 case XML_ENTITY_NODE:
7706 case XML_PI_NODE:
7707 case XML_COMMENT_NODE:
7708 case XML_NOTATION_NODE:
7709 case XML_DTD_NODE:
7710 return(ctxt->context->node->children);
7711 case XML_DOCUMENT_NODE:
7712 case XML_DOCUMENT_TYPE_NODE:
7713 case XML_DOCUMENT_FRAG_NODE:
7714 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007715#ifdef LIBXML_DOCB_ENABLED
7716 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007717#endif
7718 return(((xmlDocPtr) ctxt->context->node)->children);
7719 case XML_ELEMENT_DECL:
7720 case XML_ATTRIBUTE_DECL:
7721 case XML_ENTITY_DECL:
7722 case XML_ATTRIBUTE_NODE:
7723 case XML_NAMESPACE_DECL:
7724 case XML_XINCLUDE_START:
7725 case XML_XINCLUDE_END:
7726 return(NULL);
7727 }
7728 return(NULL);
7729 }
7730 if ((cur->type == XML_DOCUMENT_NODE) ||
7731 (cur->type == XML_HTML_DOCUMENT_NODE))
7732 return(NULL);
7733 return(cur->next);
7734}
7735
7736/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007737 * xmlXPathNextChildElement:
7738 * @ctxt: the XPath Parser context
7739 * @cur: the current node in the traversal
7740 *
7741 * Traversal function for the "child" direction and nodes of type element.
7742 * The child axis contains the children of the context node in document order.
7743 *
7744 * Returns the next element following that axis
7745 */
7746static xmlNodePtr
7747xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7748 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7749 if (cur == NULL) {
7750 cur = ctxt->context->node;
7751 if (cur == NULL) return(NULL);
7752 /*
7753 * Get the first element child.
7754 */
7755 switch (cur->type) {
7756 case XML_ELEMENT_NODE:
7757 case XML_DOCUMENT_FRAG_NODE:
7758 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7759 case XML_ENTITY_NODE:
7760 cur = cur->children;
7761 if (cur != NULL) {
7762 if (cur->type == XML_ELEMENT_NODE)
7763 return(cur);
7764 do {
7765 cur = cur->next;
7766 } while ((cur != NULL) &&
7767 (cur->type != XML_ELEMENT_NODE));
7768 return(cur);
7769 }
7770 return(NULL);
7771 case XML_DOCUMENT_NODE:
7772 case XML_HTML_DOCUMENT_NODE:
7773#ifdef LIBXML_DOCB_ENABLED
7774 case XML_DOCB_DOCUMENT_NODE:
7775#endif
7776 return(xmlDocGetRootElement((xmlDocPtr) cur));
7777 default:
7778 return(NULL);
7779 }
7780 return(NULL);
7781 }
7782 /*
7783 * Get the next sibling element node.
7784 */
7785 switch (cur->type) {
7786 case XML_ELEMENT_NODE:
7787 case XML_TEXT_NODE:
7788 case XML_ENTITY_REF_NODE:
7789 case XML_ENTITY_NODE:
7790 case XML_CDATA_SECTION_NODE:
7791 case XML_PI_NODE:
7792 case XML_COMMENT_NODE:
7793 case XML_XINCLUDE_END:
7794 break;
7795 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7796 default:
7797 return(NULL);
7798 }
7799 if (cur->next != NULL) {
7800 if (cur->next->type == XML_ELEMENT_NODE)
7801 return(cur->next);
7802 cur = cur->next;
7803 do {
7804 cur = cur->next;
7805 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7806 return(cur);
7807 }
7808 return(NULL);
7809}
7810
Daniel Veillard76516062012-09-11 14:02:08 +08007811#if 0
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007812/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007813 * xmlXPathNextDescendantOrSelfElemParent:
7814 * @ctxt: the XPath Parser context
7815 * @cur: the current node in the traversal
7816 *
7817 * Traversal function for the "descendant-or-self" axis.
7818 * Additionally it returns only nodes which can be parents of
7819 * element nodes.
7820 *
7821 *
7822 * Returns the next element following that axis
7823 */
7824static xmlNodePtr
7825xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7826 xmlNodePtr contextNode)
7827{
7828 if (cur == NULL) {
7829 if (contextNode == NULL)
7830 return(NULL);
7831 switch (contextNode->type) {
7832 case XML_ELEMENT_NODE:
7833 case XML_XINCLUDE_START:
7834 case XML_DOCUMENT_FRAG_NODE:
7835 case XML_DOCUMENT_NODE:
7836#ifdef LIBXML_DOCB_ENABLED
7837 case XML_DOCB_DOCUMENT_NODE:
7838#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007839 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007840 return(contextNode);
7841 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007842 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007843 }
7844 return(NULL);
7845 } else {
7846 xmlNodePtr start = cur;
7847
7848 while (cur != NULL) {
7849 switch (cur->type) {
7850 case XML_ELEMENT_NODE:
7851 /* TODO: OK to have XInclude here? */
7852 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007853 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007854 if (cur != start)
7855 return(cur);
7856 if (cur->children != NULL) {
7857 cur = cur->children;
7858 continue;
7859 }
7860 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007861 /* Not sure if we need those here. */
7862 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007863#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007864 case XML_DOCB_DOCUMENT_NODE:
7865#endif
7866 case XML_HTML_DOCUMENT_NODE:
7867 if (cur != start)
7868 return(cur);
7869 return(xmlDocGetRootElement((xmlDocPtr) cur));
7870 default:
7871 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007872 }
7873
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007874next_sibling:
7875 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007876 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007877 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007878 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007879 } else {
7880 cur = cur->parent;
7881 goto next_sibling;
7882 }
7883 }
7884 }
7885 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007886}
Daniel Veillard76516062012-09-11 14:02:08 +08007887#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007888
7889/**
Owen Taylor3473f882001-02-23 17:55:21 +00007890 * xmlXPathNextDescendant:
7891 * @ctxt: the XPath Parser context
7892 * @cur: the current node in the traversal
7893 *
7894 * Traversal function for the "descendant" direction
7895 * the descendant axis contains the descendants of the context node in document
7896 * order; a descendant is a child or a child of a child and so on.
7897 *
7898 * Returns the next element following that axis
7899 */
7900xmlNodePtr
7901xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007902 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007903 if (cur == NULL) {
7904 if (ctxt->context->node == NULL)
7905 return(NULL);
7906 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7907 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7908 return(NULL);
7909
7910 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7911 return(ctxt->context->doc->children);
7912 return(ctxt->context->node->children);
7913 }
7914
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007915 if (cur->type == XML_NAMESPACE_DECL)
7916 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007917 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007918 /*
7919 * Do not descend on entities declarations
7920 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007921 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007922 cur = cur->children;
7923 /*
7924 * Skip DTDs
7925 */
7926 if (cur->type != XML_DTD_NODE)
7927 return(cur);
7928 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007929 }
7930
7931 if (cur == ctxt->context->node) return(NULL);
7932
Daniel Veillard68e9e742002-11-16 15:35:11 +00007933 while (cur->next != NULL) {
7934 cur = cur->next;
7935 if ((cur->type != XML_ENTITY_DECL) &&
7936 (cur->type != XML_DTD_NODE))
7937 return(cur);
7938 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007939
Owen Taylor3473f882001-02-23 17:55:21 +00007940 do {
7941 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007942 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007943 if (cur == ctxt->context->node) return(NULL);
7944 if (cur->next != NULL) {
7945 cur = cur->next;
7946 return(cur);
7947 }
7948 } while (cur != NULL);
7949 return(cur);
7950}
7951
7952/**
7953 * xmlXPathNextDescendantOrSelf:
7954 * @ctxt: the XPath Parser context
7955 * @cur: the current node in the traversal
7956 *
7957 * Traversal function for the "descendant-or-self" direction
7958 * the descendant-or-self axis contains the context node and the descendants
7959 * of the context node in document order; thus the context node is the first
7960 * node on the axis, and the first child of the context node is the second node
7961 * on the axis
7962 *
7963 * Returns the next element following that axis
7964 */
7965xmlNodePtr
7966xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007967 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007968 if (cur == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007969 return(ctxt->context->node);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007970
7971 if (ctxt->context->node == NULL)
7972 return(NULL);
7973 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7974 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7975 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007976
7977 return(xmlXPathNextDescendant(ctxt, cur));
7978}
7979
7980/**
7981 * xmlXPathNextParent:
7982 * @ctxt: the XPath Parser context
7983 * @cur: the current node in the traversal
7984 *
7985 * Traversal function for the "parent" direction
7986 * The parent axis contains the parent of the context node, if there is one.
7987 *
7988 * Returns the next element following that axis
7989 */
7990xmlNodePtr
7991xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007992 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007993 /*
7994 * the parent of an attribute or namespace node is the element
7995 * to which the attribute or namespace node is attached
7996 * Namespace handling !!!
7997 */
7998 if (cur == NULL) {
7999 if (ctxt->context->node == NULL) return(NULL);
8000 switch (ctxt->context->node->type) {
8001 case XML_ELEMENT_NODE:
8002 case XML_TEXT_NODE:
8003 case XML_CDATA_SECTION_NODE:
8004 case XML_ENTITY_REF_NODE:
8005 case XML_ENTITY_NODE:
8006 case XML_PI_NODE:
8007 case XML_COMMENT_NODE:
8008 case XML_NOTATION_NODE:
8009 case XML_DTD_NODE:
8010 case XML_ELEMENT_DECL:
8011 case XML_ATTRIBUTE_DECL:
8012 case XML_XINCLUDE_START:
8013 case XML_XINCLUDE_END:
8014 case XML_ENTITY_DECL:
8015 if (ctxt->context->node->parent == NULL)
8016 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008017 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008018 ((ctxt->context->node->parent->name[0] == ' ') ||
8019 (xmlStrEqual(ctxt->context->node->parent->name,
8020 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008021 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008022 return(ctxt->context->node->parent);
8023 case XML_ATTRIBUTE_NODE: {
8024 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8025
8026 return(att->parent);
8027 }
8028 case XML_DOCUMENT_NODE:
8029 case XML_DOCUMENT_TYPE_NODE:
8030 case XML_DOCUMENT_FRAG_NODE:
8031 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008032#ifdef LIBXML_DOCB_ENABLED
8033 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008034#endif
8035 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008036 case XML_NAMESPACE_DECL: {
8037 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008038
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008039 if ((ns->next != NULL) &&
8040 (ns->next->type != XML_NAMESPACE_DECL))
8041 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00008042 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008043 }
Owen Taylor3473f882001-02-23 17:55:21 +00008044 }
8045 }
8046 return(NULL);
8047}
8048
8049/**
8050 * xmlXPathNextAncestor:
8051 * @ctxt: the XPath Parser context
8052 * @cur: the current node in the traversal
8053 *
8054 * Traversal function for the "ancestor" direction
8055 * the ancestor axis contains the ancestors of the context node; the ancestors
8056 * of the context node consist of the parent of context node and the parent's
8057 * parent and so on; the nodes are ordered in reverse document order; thus the
8058 * parent is the first node on the axis, and the parent's parent is the second
8059 * node on the axis
8060 *
8061 * Returns the next element following that axis
8062 */
8063xmlNodePtr
8064xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008065 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008066 /*
8067 * the parent of an attribute or namespace node is the element
8068 * to which the attribute or namespace node is attached
8069 * !!!!!!!!!!!!!
8070 */
8071 if (cur == NULL) {
8072 if (ctxt->context->node == NULL) return(NULL);
8073 switch (ctxt->context->node->type) {
8074 case XML_ELEMENT_NODE:
8075 case XML_TEXT_NODE:
8076 case XML_CDATA_SECTION_NODE:
8077 case XML_ENTITY_REF_NODE:
8078 case XML_ENTITY_NODE:
8079 case XML_PI_NODE:
8080 case XML_COMMENT_NODE:
8081 case XML_DTD_NODE:
8082 case XML_ELEMENT_DECL:
8083 case XML_ATTRIBUTE_DECL:
8084 case XML_ENTITY_DECL:
8085 case XML_NOTATION_NODE:
8086 case XML_XINCLUDE_START:
8087 case XML_XINCLUDE_END:
8088 if (ctxt->context->node->parent == NULL)
8089 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008090 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008091 ((ctxt->context->node->parent->name[0] == ' ') ||
8092 (xmlStrEqual(ctxt->context->node->parent->name,
8093 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008094 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008095 return(ctxt->context->node->parent);
8096 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008097 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00008098
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008099 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00008100 }
8101 case XML_DOCUMENT_NODE:
8102 case XML_DOCUMENT_TYPE_NODE:
8103 case XML_DOCUMENT_FRAG_NODE:
8104 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008105#ifdef LIBXML_DOCB_ENABLED
8106 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008107#endif
8108 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008109 case XML_NAMESPACE_DECL: {
8110 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008111
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008112 if ((ns->next != NULL) &&
8113 (ns->next->type != XML_NAMESPACE_DECL))
8114 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008115 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008116 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008117 }
Owen Taylor3473f882001-02-23 17:55:21 +00008118 }
8119 return(NULL);
8120 }
8121 if (cur == ctxt->context->doc->children)
8122 return((xmlNodePtr) ctxt->context->doc);
8123 if (cur == (xmlNodePtr) ctxt->context->doc)
8124 return(NULL);
8125 switch (cur->type) {
8126 case XML_ELEMENT_NODE:
8127 case XML_TEXT_NODE:
8128 case XML_CDATA_SECTION_NODE:
8129 case XML_ENTITY_REF_NODE:
8130 case XML_ENTITY_NODE:
8131 case XML_PI_NODE:
8132 case XML_COMMENT_NODE:
8133 case XML_NOTATION_NODE:
8134 case XML_DTD_NODE:
8135 case XML_ELEMENT_DECL:
8136 case XML_ATTRIBUTE_DECL:
8137 case XML_ENTITY_DECL:
8138 case XML_XINCLUDE_START:
8139 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008140 if (cur->parent == NULL)
8141 return(NULL);
8142 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008143 ((cur->parent->name[0] == ' ') ||
8144 (xmlStrEqual(cur->parent->name,
8145 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008146 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008147 return(cur->parent);
8148 case XML_ATTRIBUTE_NODE: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008149 xmlAttrPtr att = (xmlAttrPtr) cur;
Owen Taylor3473f882001-02-23 17:55:21 +00008150
8151 return(att->parent);
8152 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008153 case XML_NAMESPACE_DECL: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008154 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008155
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008156 if ((ns->next != NULL) &&
8157 (ns->next->type != XML_NAMESPACE_DECL))
8158 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008159 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008160 return(NULL);
8161 }
Owen Taylor3473f882001-02-23 17:55:21 +00008162 case XML_DOCUMENT_NODE:
8163 case XML_DOCUMENT_TYPE_NODE:
8164 case XML_DOCUMENT_FRAG_NODE:
8165 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008166#ifdef LIBXML_DOCB_ENABLED
8167 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008168#endif
8169 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008170 }
8171 return(NULL);
8172}
8173
8174/**
8175 * xmlXPathNextAncestorOrSelf:
8176 * @ctxt: the XPath Parser context
8177 * @cur: the current node in the traversal
8178 *
8179 * Traversal function for the "ancestor-or-self" direction
8180 * he ancestor-or-self axis contains the context node and ancestors of
8181 * the context node in reverse document order; thus the context node is
8182 * the first node on the axis, and the context node's parent the second;
8183 * parent here is defined the same as with the parent axis.
8184 *
8185 * Returns the next element following that axis
8186 */
8187xmlNodePtr
8188xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008189 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008190 if (cur == NULL)
8191 return(ctxt->context->node);
8192 return(xmlXPathNextAncestor(ctxt, cur));
8193}
8194
8195/**
8196 * xmlXPathNextFollowingSibling:
8197 * @ctxt: the XPath Parser context
8198 * @cur: the current node in the traversal
8199 *
8200 * Traversal function for the "following-sibling" direction
8201 * The following-sibling axis contains the following siblings of the context
8202 * node in document order.
8203 *
8204 * Returns the next element following that axis
8205 */
8206xmlNodePtr
8207xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008208 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008209 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8210 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8211 return(NULL);
8212 if (cur == (xmlNodePtr) ctxt->context->doc)
8213 return(NULL);
8214 if (cur == NULL)
8215 return(ctxt->context->node->next);
8216 return(cur->next);
8217}
8218
8219/**
8220 * xmlXPathNextPrecedingSibling:
8221 * @ctxt: the XPath Parser context
8222 * @cur: the current node in the traversal
8223 *
8224 * Traversal function for the "preceding-sibling" direction
8225 * The preceding-sibling axis contains the preceding siblings of the context
8226 * node in reverse document order; the first preceding sibling is first on the
8227 * axis; the sibling preceding that node is the second on the axis and so on.
8228 *
8229 * Returns the next element following that axis
8230 */
8231xmlNodePtr
8232xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008233 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008234 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8235 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8236 return(NULL);
8237 if (cur == (xmlNodePtr) ctxt->context->doc)
8238 return(NULL);
8239 if (cur == NULL)
8240 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008241 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8242 cur = cur->prev;
8243 if (cur == NULL)
8244 return(ctxt->context->node->prev);
8245 }
Owen Taylor3473f882001-02-23 17:55:21 +00008246 return(cur->prev);
8247}
8248
8249/**
8250 * xmlXPathNextFollowing:
8251 * @ctxt: the XPath Parser context
8252 * @cur: the current node in the traversal
8253 *
8254 * Traversal function for the "following" direction
8255 * The following axis contains all nodes in the same document as the context
8256 * node that are after the context node in document order, excluding any
8257 * descendants and excluding attribute nodes and namespace nodes; the nodes
8258 * are ordered in document order
8259 *
8260 * Returns the next element following that axis
8261 */
8262xmlNodePtr
8263xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008264 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008265 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8266 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8267 return(cur->children);
8268
8269 if (cur == NULL) {
8270 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008271 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardea90b892010-10-22 15:50:50 +02008272 cur = cur->parent;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008273 } else if (cur->type == XML_NAMESPACE_DECL) {
8274 xmlNsPtr ns = (xmlNsPtr) cur;
8275
8276 if ((ns->next == NULL) ||
8277 (ns->next->type == XML_NAMESPACE_DECL))
8278 return (NULL);
8279 cur = (xmlNodePtr) ns->next;
8280 }
Daniel Veillard91d19752010-10-15 14:30:52 +02008281 }
Owen Taylor3473f882001-02-23 17:55:21 +00008282 if (cur == NULL) return(NULL) ; /* ERROR */
8283 if (cur->next != NULL) return(cur->next) ;
8284 do {
8285 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008286 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008287 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8288 if (cur->next != NULL) return(cur->next);
8289 } while (cur != NULL);
8290 return(cur);
8291}
8292
8293/*
8294 * xmlXPathIsAncestor:
8295 * @ancestor: the ancestor node
8296 * @node: the current node
8297 *
8298 * Check that @ancestor is a @node's ancestor
8299 *
8300 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8301 */
8302static int
8303xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8304 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008305 if (node->type == XML_NAMESPACE_DECL)
8306 return(0);
8307 if (ancestor->type == XML_NAMESPACE_DECL)
8308 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008309 /* nodes need to be in the same document */
8310 if (ancestor->doc != node->doc) return(0);
8311 /* avoid searching if ancestor or node is the root node */
8312 if (ancestor == (xmlNodePtr) node->doc) return(1);
8313 if (node == (xmlNodePtr) ancestor->doc) return(0);
8314 while (node->parent != NULL) {
8315 if (node->parent == ancestor)
8316 return(1);
8317 node = node->parent;
8318 }
8319 return(0);
8320}
8321
8322/**
8323 * xmlXPathNextPreceding:
8324 * @ctxt: the XPath Parser context
8325 * @cur: the current node in the traversal
8326 *
8327 * Traversal function for the "preceding" direction
8328 * the preceding axis contains all nodes in the same document as the context
8329 * node that are before the context node in document order, excluding any
8330 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8331 * ordered in reverse document order
8332 *
8333 * Returns the next element following that axis
8334 */
8335xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008336xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8337{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008338 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008339 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008340 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008341 if (cur->type == XML_ATTRIBUTE_NODE) {
8342 cur = cur->parent;
8343 } else if (cur->type == XML_NAMESPACE_DECL) {
8344 xmlNsPtr ns = (xmlNsPtr) cur;
8345
8346 if ((ns->next == NULL) ||
8347 (ns->next->type == XML_NAMESPACE_DECL))
8348 return (NULL);
8349 cur = (xmlNodePtr) ns->next;
8350 }
Daniel Veillardea90b892010-10-22 15:50:50 +02008351 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008352 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008353 return (NULL);
8354 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8355 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008356 do {
8357 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008358 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8359 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008360 }
8361
8362 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008363 if (cur == NULL)
8364 return (NULL);
8365 if (cur == ctxt->context->doc->children)
8366 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008367 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008368 return (cur);
8369}
8370
8371/**
8372 * xmlXPathNextPrecedingInternal:
8373 * @ctxt: the XPath Parser context
8374 * @cur: the current node in the traversal
8375 *
8376 * Traversal function for the "preceding" direction
8377 * the preceding axis contains all nodes in the same document as the context
8378 * node that are before the context node in document order, excluding any
8379 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8380 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008381 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008382 * state kept in the parser context: ctxt->ancestor.
8383 *
8384 * Returns the next element following that axis
8385 */
8386static xmlNodePtr
8387xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8388 xmlNodePtr cur)
8389{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008390 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008391 if (cur == NULL) {
8392 cur = ctxt->context->node;
8393 if (cur == NULL)
8394 return (NULL);
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008395 if (cur->type == XML_ATTRIBUTE_NODE) {
8396 cur = cur->parent;
8397 } else if (cur->type == XML_NAMESPACE_DECL) {
8398 xmlNsPtr ns = (xmlNsPtr) cur;
8399
8400 if ((ns->next == NULL) ||
8401 (ns->next->type == XML_NAMESPACE_DECL))
8402 return (NULL);
8403 cur = (xmlNodePtr) ns->next;
8404 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00008405 ctxt->ancestor = cur->parent;
8406 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008407 if (cur->type == XML_NAMESPACE_DECL)
8408 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008409 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8410 cur = cur->prev;
8411 while (cur->prev == NULL) {
8412 cur = cur->parent;
8413 if (cur == NULL)
8414 return (NULL);
8415 if (cur == ctxt->context->doc->children)
8416 return (NULL);
8417 if (cur != ctxt->ancestor)
8418 return (cur);
8419 ctxt->ancestor = cur->parent;
8420 }
8421 cur = cur->prev;
8422 while (cur->last != NULL)
8423 cur = cur->last;
8424 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008425}
8426
8427/**
8428 * xmlXPathNextNamespace:
8429 * @ctxt: the XPath Parser context
8430 * @cur: the current attribute in the traversal
8431 *
8432 * Traversal function for the "namespace" direction
8433 * the namespace axis contains the namespace nodes of the context node;
8434 * the order of nodes on this axis is implementation-defined; the axis will
8435 * be empty unless the context node is an element
8436 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008437 * We keep the XML namespace node at the end of the list.
8438 *
Owen Taylor3473f882001-02-23 17:55:21 +00008439 * Returns the next element following that axis
8440 */
8441xmlNodePtr
8442xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008443 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008444 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Nick Wellnhofer82b73032016-04-30 17:53:10 +02008445 if (cur == NULL) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008446 if (ctxt->context->tmpNsList != NULL)
8447 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008448 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008449 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008450 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008451 if (ctxt->context->tmpNsList != NULL) {
8452 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8453 ctxt->context->tmpNsNr++;
8454 }
8455 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008456 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008457 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008458 if (ctxt->context->tmpNsNr > 0) {
8459 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8460 } else {
8461 if (ctxt->context->tmpNsList != NULL)
8462 xmlFree(ctxt->context->tmpNsList);
8463 ctxt->context->tmpNsList = NULL;
8464 return(NULL);
8465 }
Owen Taylor3473f882001-02-23 17:55:21 +00008466}
8467
8468/**
8469 * xmlXPathNextAttribute:
8470 * @ctxt: the XPath Parser context
8471 * @cur: the current attribute in the traversal
8472 *
8473 * Traversal function for the "attribute" direction
8474 * TODO: support DTD inherited default attributes
8475 *
8476 * Returns the next element following that axis
8477 */
8478xmlNodePtr
8479xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008480 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008481 if (ctxt->context->node == NULL)
8482 return(NULL);
8483 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8484 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008485 if (cur == NULL) {
8486 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8487 return(NULL);
8488 return((xmlNodePtr)ctxt->context->node->properties);
8489 }
8490 return((xmlNodePtr)cur->next);
8491}
8492
8493/************************************************************************
8494 * *
8495 * NodeTest Functions *
8496 * *
8497 ************************************************************************/
8498
Owen Taylor3473f882001-02-23 17:55:21 +00008499#define IS_FUNCTION 200
8500
Owen Taylor3473f882001-02-23 17:55:21 +00008501
8502/************************************************************************
8503 * *
8504 * Implicit tree core function library *
8505 * *
8506 ************************************************************************/
8507
8508/**
8509 * xmlXPathRoot:
8510 * @ctxt: the XPath Parser context
8511 *
8512 * Initialize the context to the root of the document
8513 */
8514void
8515xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008516 if ((ctxt == NULL) || (ctxt->context == NULL))
8517 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008518 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008519 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8520 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008521}
8522
8523/************************************************************************
8524 * *
8525 * The explicit core function library *
8526 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8527 * *
8528 ************************************************************************/
8529
8530
8531/**
8532 * xmlXPathLastFunction:
8533 * @ctxt: the XPath Parser context
8534 * @nargs: the number of arguments
8535 *
8536 * Implement the last() XPath function
8537 * number last()
8538 * The last function returns the number of nodes in the context node list.
8539 */
8540void
8541xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8542 CHECK_ARITY(0);
8543 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008544 valuePush(ctxt,
8545 xmlXPathCacheNewFloat(ctxt->context,
8546 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008547#ifdef DEBUG_EXPR
8548 xmlGenericError(xmlGenericErrorContext,
8549 "last() : %d\n", ctxt->context->contextSize);
8550#endif
8551 } else {
8552 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8553 }
8554}
8555
8556/**
8557 * xmlXPathPositionFunction:
8558 * @ctxt: the XPath Parser context
8559 * @nargs: the number of arguments
8560 *
8561 * Implement the position() XPath function
8562 * number position()
8563 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008564 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008565 * will be equal to last().
8566 */
8567void
8568xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8569 CHECK_ARITY(0);
8570 if (ctxt->context->proximityPosition >= 0) {
8571 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008572 xmlXPathCacheNewFloat(ctxt->context,
8573 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008574#ifdef DEBUG_EXPR
8575 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8576 ctxt->context->proximityPosition);
8577#endif
8578 } else {
8579 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8580 }
8581}
8582
8583/**
8584 * xmlXPathCountFunction:
8585 * @ctxt: the XPath Parser context
8586 * @nargs: the number of arguments
8587 *
8588 * Implement the count() XPath function
8589 * number count(node-set)
8590 */
8591void
8592xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8593 xmlXPathObjectPtr cur;
8594
8595 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008596 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008597 ((ctxt->value->type != XPATH_NODESET) &&
8598 (ctxt->value->type != XPATH_XSLT_TREE)))
8599 XP_ERROR(XPATH_INVALID_TYPE);
8600 cur = valuePop(ctxt);
8601
Daniel Veillard911f49a2001-04-07 15:39:35 +00008602 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008603 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008604 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008605 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8606 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008607 } else {
8608 if ((cur->nodesetval->nodeNr != 1) ||
8609 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008610 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008611 } else {
8612 xmlNodePtr tmp;
8613 int i = 0;
8614
8615 tmp = cur->nodesetval->nodeTab[0];
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008616 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
Daniel Veillardfe703322001-08-14 12:18:09 +00008617 tmp = tmp->children;
8618 while (tmp != NULL) {
8619 tmp = tmp->next;
8620 i++;
8621 }
8622 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008623 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008624 }
8625 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008626 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008627}
8628
8629/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008630 * xmlXPathGetElementsByIds:
8631 * @doc: the document
8632 * @ids: a whitespace separated list of IDs
8633 *
8634 * Selects elements by their unique ID.
8635 *
8636 * Returns a node-set of selected elements.
8637 */
8638static xmlNodeSetPtr
8639xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8640 xmlNodeSetPtr ret;
8641 const xmlChar *cur = ids;
8642 xmlChar *ID;
8643 xmlAttrPtr attr;
8644 xmlNodePtr elem = NULL;
8645
Daniel Veillard7a985a12003-07-06 17:57:42 +00008646 if (ids == NULL) return(NULL);
8647
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008648 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008649 if (ret == NULL)
8650 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008651
William M. Brack76e95df2003-10-18 16:20:14 +00008652 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008653 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008654 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008655 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008656
8657 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008658 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008659 /*
8660 * We used to check the fact that the value passed
8661 * was an NCName, but this generated much troubles for
8662 * me and Aleksey Sanin, people blatantly violated that
8663 * constaint, like Visa3D spec.
8664 * if (xmlValidateNCName(ID, 1) == 0)
8665 */
8666 attr = xmlGetID(doc, ID);
8667 if (attr != NULL) {
8668 if (attr->type == XML_ATTRIBUTE_NODE)
8669 elem = attr->parent;
8670 else if (attr->type == XML_ELEMENT_NODE)
8671 elem = (xmlNodePtr) attr;
8672 else
8673 elem = NULL;
8674 if (elem != NULL)
8675 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008676 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008677 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008678 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008679
William M. Brack76e95df2003-10-18 16:20:14 +00008680 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008681 ids = cur;
8682 }
8683 return(ret);
8684}
8685
8686/**
Owen Taylor3473f882001-02-23 17:55:21 +00008687 * xmlXPathIdFunction:
8688 * @ctxt: the XPath Parser context
8689 * @nargs: the number of arguments
8690 *
8691 * Implement the id() XPath function
8692 * node-set id(object)
8693 * The id function selects elements by their unique ID
8694 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8695 * then the result is the union of the result of applying id to the
8696 * string value of each of the nodes in the argument node-set. When the
8697 * argument to id is of any other type, the argument is converted to a
8698 * string as if by a call to the string function; the string is split
8699 * into a whitespace-separated list of tokens (whitespace is any sequence
8700 * of characters matching the production S); the result is a node-set
8701 * containing the elements in the same document as the context node that
8702 * have a unique ID equal to any of the tokens in the list.
8703 */
8704void
8705xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008706 xmlChar *tokens;
8707 xmlNodeSetPtr ret;
8708 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008709
8710 CHECK_ARITY(1);
8711 obj = valuePop(ctxt);
8712 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008713 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008714 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008715 int i;
8716
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008717 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008718 /*
8719 * FIXME -- in an out-of-memory condition this will behave badly.
8720 * The solution is not clear -- we already popped an item from
8721 * ctxt, so the object is in a corrupt state.
8722 */
Owen Taylor3473f882001-02-23 17:55:21 +00008723
Daniel Veillard911f49a2001-04-07 15:39:35 +00008724 if (obj->nodesetval != NULL) {
8725 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008726 tokens =
8727 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8728 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8729 ret = xmlXPathNodeSetMerge(ret, ns);
8730 xmlXPathFreeNodeSet(ns);
8731 if (tokens != NULL)
8732 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008733 }
Owen Taylor3473f882001-02-23 17:55:21 +00008734 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008735 xmlXPathReleaseObject(ctxt->context, obj);
8736 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008737 return;
8738 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008739 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008740 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008741 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008742 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008743 return;
8744}
8745
8746/**
8747 * xmlXPathLocalNameFunction:
8748 * @ctxt: the XPath Parser context
8749 * @nargs: the number of arguments
8750 *
8751 * Implement the local-name() XPath function
8752 * string local-name(node-set?)
8753 * The local-name function returns a string containing the local part
8754 * of the name of the node in the argument node-set that is first in
8755 * document order. If the node-set is empty or the first node has no
8756 * name, an empty string is returned. If the argument is omitted it
8757 * defaults to the context node.
8758 */
8759void
8760xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8761 xmlXPathObjectPtr cur;
8762
Daniel Veillarda82b1822004-11-08 16:24:57 +00008763 if (ctxt == NULL) return;
8764
Owen Taylor3473f882001-02-23 17:55:21 +00008765 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008766 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8767 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008768 nargs = 1;
8769 }
8770
8771 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008772 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008773 ((ctxt->value->type != XPATH_NODESET) &&
8774 (ctxt->value->type != XPATH_XSLT_TREE)))
8775 XP_ERROR(XPATH_INVALID_TYPE);
8776 cur = valuePop(ctxt);
8777
Daniel Veillard911f49a2001-04-07 15:39:35 +00008778 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008779 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008780 } else {
8781 int i = 0; /* Should be first in document order !!!!! */
8782 switch (cur->nodesetval->nodeTab[i]->type) {
8783 case XML_ELEMENT_NODE:
8784 case XML_ATTRIBUTE_NODE:
8785 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008786 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008787 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008788 else
8789 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008790 xmlXPathCacheNewString(ctxt->context,
8791 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008792 break;
8793 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008794 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008795 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8796 break;
8797 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008798 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008799 }
8800 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008801 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008802}
8803
8804/**
8805 * xmlXPathNamespaceURIFunction:
8806 * @ctxt: the XPath Parser context
8807 * @nargs: the number of arguments
8808 *
8809 * Implement the namespace-uri() XPath function
8810 * string namespace-uri(node-set?)
8811 * The namespace-uri function returns a string containing the
8812 * namespace URI of the expanded name of the node in the argument
8813 * node-set that is first in document order. If the node-set is empty,
8814 * the first node has no name, or the expanded name has no namespace
8815 * URI, an empty string is returned. If the argument is omitted it
8816 * defaults to the context node.
8817 */
8818void
8819xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8820 xmlXPathObjectPtr cur;
8821
Daniel Veillarda82b1822004-11-08 16:24:57 +00008822 if (ctxt == NULL) return;
8823
Owen Taylor3473f882001-02-23 17:55:21 +00008824 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008825 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8826 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008827 nargs = 1;
8828 }
8829 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008830 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008831 ((ctxt->value->type != XPATH_NODESET) &&
8832 (ctxt->value->type != XPATH_XSLT_TREE)))
8833 XP_ERROR(XPATH_INVALID_TYPE);
8834 cur = valuePop(ctxt);
8835
Daniel Veillard911f49a2001-04-07 15:39:35 +00008836 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008837 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008838 } else {
8839 int i = 0; /* Should be first in document order !!!!! */
8840 switch (cur->nodesetval->nodeTab[i]->type) {
8841 case XML_ELEMENT_NODE:
8842 case XML_ATTRIBUTE_NODE:
8843 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008844 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008845 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008846 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008847 cur->nodesetval->nodeTab[i]->ns->href));
8848 break;
8849 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008850 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008851 }
8852 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008853 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008854}
8855
8856/**
8857 * xmlXPathNameFunction:
8858 * @ctxt: the XPath Parser context
8859 * @nargs: the number of arguments
8860 *
8861 * Implement the name() XPath function
8862 * string name(node-set?)
8863 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008864 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008865 * order. The QName must represent the name with respect to the namespace
8866 * declarations in effect on the node whose name is being represented.
8867 * Typically, this will be the form in which the name occurred in the XML
8868 * source. This need not be the case if there are namespace declarations
8869 * in effect on the node that associate multiple prefixes with the same
8870 * namespace. However, an implementation may include information about
8871 * the original prefix in its representation of nodes; in this case, an
8872 * implementation can ensure that the returned string is always the same
8873 * as the QName used in the XML source. If the argument it omitted it
8874 * defaults to the context node.
8875 * Libxml keep the original prefix so the "real qualified name" used is
8876 * returned.
8877 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008878static void
Daniel Veillard04383752001-07-08 14:27:15 +00008879xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8880{
Owen Taylor3473f882001-02-23 17:55:21 +00008881 xmlXPathObjectPtr cur;
8882
8883 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008884 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8885 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008886 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008887 }
8888
8889 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008890 if ((ctxt->value == NULL) ||
8891 ((ctxt->value->type != XPATH_NODESET) &&
8892 (ctxt->value->type != XPATH_XSLT_TREE)))
8893 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008894 cur = valuePop(ctxt);
8895
Daniel Veillard911f49a2001-04-07 15:39:35 +00008896 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008897 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008898 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008899 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008900
Daniel Veillard04383752001-07-08 14:27:15 +00008901 switch (cur->nodesetval->nodeTab[i]->type) {
8902 case XML_ELEMENT_NODE:
8903 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008904 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008905 valuePush(ctxt,
8906 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008907 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8908 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008909 valuePush(ctxt,
8910 xmlXPathCacheNewString(ctxt->context,
8911 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008912 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008913 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008914
Daniel Veillardc00cda82003-04-07 10:22:39 +00008915 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8916 cur->nodesetval->nodeTab[i]->ns->prefix,
8917 NULL, 0);
8918 if (fullname == cur->nodesetval->nodeTab[i]->name)
8919 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8920 if (fullname == NULL) {
8921 XP_ERROR(XPATH_MEMORY_ERROR);
8922 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008923 valuePush(ctxt, xmlXPathCacheWrapString(
8924 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008925 }
8926 break;
8927 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008928 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8929 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008930 xmlXPathLocalNameFunction(ctxt, 1);
8931 }
Owen Taylor3473f882001-02-23 17:55:21 +00008932 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008933 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008934}
8935
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008936
8937/**
Owen Taylor3473f882001-02-23 17:55:21 +00008938 * xmlXPathStringFunction:
8939 * @ctxt: the XPath Parser context
8940 * @nargs: the number of arguments
8941 *
8942 * Implement the string() XPath function
8943 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008944 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008945 * - A node-set is converted to a string by returning the value of
8946 * the node in the node-set that is first in document order.
8947 * If the node-set is empty, an empty string is returned.
8948 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008949 * + NaN is converted to the string NaN
8950 * + positive zero is converted to the string 0
8951 * + negative zero is converted to the string 0
8952 * + positive infinity is converted to the string Infinity
8953 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008954 * + if the number is an integer, the number is represented in
8955 * decimal form as a Number with no decimal point and no leading
8956 * zeros, preceded by a minus sign (-) if the number is negative
8957 * + otherwise, the number is represented in decimal form as a
8958 * Number including a decimal point with at least one digit
8959 * before the decimal point and at least one digit after the
8960 * decimal point, preceded by a minus sign (-) if the number
8961 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008962 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008963 * before the decimal point; beyond the one required digit
8964 * after the decimal point there must be as many, but only as
8965 * many, more digits as are needed to uniquely distinguish the
8966 * number from all other IEEE 754 numeric values.
8967 * - The boolean false value is converted to the string false.
8968 * The boolean true value is converted to the string true.
8969 *
8970 * If the argument is omitted, it defaults to a node-set with the
8971 * context node as its only member.
8972 */
8973void
8974xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8975 xmlXPathObjectPtr cur;
8976
Daniel Veillarda82b1822004-11-08 16:24:57 +00008977 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008978 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008979 valuePush(ctxt,
8980 xmlXPathCacheWrapString(ctxt->context,
8981 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008982 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008983 }
8984
8985 CHECK_ARITY(1);
8986 cur = valuePop(ctxt);
8987 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008988 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008989}
8990
8991/**
8992 * xmlXPathStringLengthFunction:
8993 * @ctxt: the XPath Parser context
8994 * @nargs: the number of arguments
8995 *
8996 * Implement the string-length() XPath function
8997 * number string-length(string?)
8998 * The string-length returns the number of characters in the string
8999 * (see [3.6 Strings]). If the argument is omitted, it defaults to
9000 * the context node converted to a string, in other words the value
9001 * of the context node.
9002 */
9003void
9004xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9005 xmlXPathObjectPtr cur;
9006
9007 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00009008 if ((ctxt == NULL) || (ctxt->context == NULL))
9009 return;
Owen Taylor3473f882001-02-23 17:55:21 +00009010 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009011 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009012 } else {
9013 xmlChar *content;
9014
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009015 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009016 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9017 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00009018 xmlFree(content);
9019 }
9020 return;
9021 }
9022 CHECK_ARITY(1);
9023 CAST_TO_STRING;
9024 CHECK_TYPE(XPATH_STRING);
9025 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009026 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00009027 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009028 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009029}
9030
9031/**
9032 * xmlXPathConcatFunction:
9033 * @ctxt: the XPath Parser context
9034 * @nargs: the number of arguments
9035 *
9036 * Implement the concat() XPath function
9037 * string concat(string, string, string*)
9038 * The concat function returns the concatenation of its arguments.
9039 */
9040void
9041xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9042 xmlXPathObjectPtr cur, newobj;
9043 xmlChar *tmp;
9044
Daniel Veillarda82b1822004-11-08 16:24:57 +00009045 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009046 if (nargs < 2) {
9047 CHECK_ARITY(2);
9048 }
9049
9050 CAST_TO_STRING;
9051 cur = valuePop(ctxt);
9052 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009053 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009054 return;
9055 }
9056 nargs--;
9057
9058 while (nargs > 0) {
9059 CAST_TO_STRING;
9060 newobj = valuePop(ctxt);
9061 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009062 xmlXPathReleaseObject(ctxt->context, newobj);
9063 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009064 XP_ERROR(XPATH_INVALID_TYPE);
9065 }
9066 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9067 newobj->stringval = cur->stringval;
9068 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009069 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00009070 nargs--;
9071 }
9072 valuePush(ctxt, cur);
9073}
9074
9075/**
9076 * xmlXPathContainsFunction:
9077 * @ctxt: the XPath Parser context
9078 * @nargs: the number of arguments
9079 *
9080 * Implement the contains() XPath function
9081 * boolean contains(string, string)
9082 * The contains function returns true if the first argument string
9083 * contains the second argument string, and otherwise returns false.
9084 */
9085void
9086xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9087 xmlXPathObjectPtr hay, needle;
9088
9089 CHECK_ARITY(2);
9090 CAST_TO_STRING;
9091 CHECK_TYPE(XPATH_STRING);
9092 needle = valuePop(ctxt);
9093 CAST_TO_STRING;
9094 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009095
Owen Taylor3473f882001-02-23 17:55:21 +00009096 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009097 xmlXPathReleaseObject(ctxt->context, hay);
9098 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009099 XP_ERROR(XPATH_INVALID_TYPE);
9100 }
9101 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009102 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009103 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009104 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9105 xmlXPathReleaseObject(ctxt->context, hay);
9106 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009107}
9108
9109/**
9110 * xmlXPathStartsWithFunction:
9111 * @ctxt: the XPath Parser context
9112 * @nargs: the number of arguments
9113 *
9114 * Implement the starts-with() XPath function
9115 * boolean starts-with(string, string)
9116 * The starts-with function returns true if the first argument string
9117 * starts with the second argument string, and otherwise returns false.
9118 */
9119void
9120xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9121 xmlXPathObjectPtr hay, needle;
9122 int n;
9123
9124 CHECK_ARITY(2);
9125 CAST_TO_STRING;
9126 CHECK_TYPE(XPATH_STRING);
9127 needle = valuePop(ctxt);
9128 CAST_TO_STRING;
9129 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009130
Owen Taylor3473f882001-02-23 17:55:21 +00009131 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009132 xmlXPathReleaseObject(ctxt->context, hay);
9133 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009134 XP_ERROR(XPATH_INVALID_TYPE);
9135 }
9136 n = xmlStrlen(needle->stringval);
9137 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009138 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009139 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009140 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9141 xmlXPathReleaseObject(ctxt->context, hay);
9142 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009143}
9144
9145/**
9146 * xmlXPathSubstringFunction:
9147 * @ctxt: the XPath Parser context
9148 * @nargs: the number of arguments
9149 *
9150 * Implement the substring() XPath function
9151 * string substring(string, number, number?)
9152 * The substring function returns the substring of the first argument
9153 * starting at the position specified in the second argument with
9154 * length specified in the third argument. For example,
9155 * substring("12345",2,3) returns "234". If the third argument is not
9156 * specified, it returns the substring starting at the position specified
9157 * in the second argument and continuing to the end of the string. For
9158 * example, substring("12345",2) returns "2345". More precisely, each
9159 * character in the string (see [3.6 Strings]) is considered to have a
9160 * numeric position: the position of the first character is 1, the position
9161 * of the second character is 2 and so on. The returned substring contains
9162 * those characters for which the position of the character is greater than
9163 * or equal to the second argument and, if the third argument is specified,
9164 * less than the sum of the second and third arguments; the comparisons
9165 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009166 * - substring("12345", 1.5, 2.6) returns "234"
9167 * - substring("12345", 0, 3) returns "12"
9168 * - substring("12345", 0 div 0, 3) returns ""
9169 * - substring("12345", 1, 0 div 0) returns ""
9170 * - substring("12345", -42, 1 div 0) returns "12345"
9171 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009172 */
9173void
9174xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9175 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009176 double le=0, in;
9177 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009178 xmlChar *ret;
9179
Owen Taylor3473f882001-02-23 17:55:21 +00009180 if (nargs < 2) {
9181 CHECK_ARITY(2);
9182 }
9183 if (nargs > 3) {
9184 CHECK_ARITY(3);
9185 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009186 /*
9187 * take care of possible last (position) argument
9188 */
Owen Taylor3473f882001-02-23 17:55:21 +00009189 if (nargs == 3) {
9190 CAST_TO_NUMBER;
9191 CHECK_TYPE(XPATH_NUMBER);
9192 len = valuePop(ctxt);
9193 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009194 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009195 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009196
Owen Taylor3473f882001-02-23 17:55:21 +00009197 CAST_TO_NUMBER;
9198 CHECK_TYPE(XPATH_NUMBER);
9199 start = valuePop(ctxt);
9200 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009201 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009202 CAST_TO_STRING;
9203 CHECK_TYPE(XPATH_STRING);
9204 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009205 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009206
Daniel Veillard97ac1312001-05-30 19:14:17 +00009207 /*
9208 * If last pos not present, calculate last position
9209 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009210 if (nargs != 3) {
9211 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009212 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009213 in = 1.0;
9214 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009215
Daniel Veillard45490ae2008-07-29 09:13:19 +00009216 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009217 * the index is NaN, the length is NaN, or both
9218 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009219 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009220 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009221 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009222 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009223 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009224 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009225 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009226 * First we go to integer form, rounding up
9227 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009228 */
9229 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009230 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009231
Daniel Veillard9e412302002-06-10 15:59:44 +00009232 if (xmlXPathIsInf(le) == 1) {
9233 l = m;
9234 if (i < 1)
9235 i = 1;
9236 }
9237 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9238 l = 0;
9239 else {
9240 l = (int) le;
9241 if (((double)l)+0.5 <= le) l++;
9242 }
9243
9244 /* Now we normalize inidices */
9245 i -= 1;
9246 l += i;
9247 if (i < 0)
9248 i = 0;
9249 if (l > m)
9250 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009251
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009252 /* number of chars to copy */
9253 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009254
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009255 ret = xmlUTF8Strsub(str->stringval, i, l);
9256 }
9257 else {
9258 ret = NULL;
9259 }
Owen Taylor3473f882001-02-23 17:55:21 +00009260 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009261 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009262 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009263 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009264 xmlFree(ret);
9265 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009266 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009267}
9268
9269/**
9270 * xmlXPathSubstringBeforeFunction:
9271 * @ctxt: the XPath Parser context
9272 * @nargs: the number of arguments
9273 *
9274 * Implement the substring-before() XPath function
9275 * string substring-before(string, string)
9276 * The substring-before function returns the substring of the first
9277 * argument string that precedes the first occurrence of the second
9278 * argument string in the first argument string, or the empty string
9279 * if the first argument string does not contain the second argument
9280 * string. For example, substring-before("1999/04/01","/") returns 1999.
9281 */
9282void
9283xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9284 xmlXPathObjectPtr str;
9285 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009286 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009287 const xmlChar *point;
9288 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009289
Owen Taylor3473f882001-02-23 17:55:21 +00009290 CHECK_ARITY(2);
9291 CAST_TO_STRING;
9292 find = valuePop(ctxt);
9293 CAST_TO_STRING;
9294 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009295
Daniel Veillardade10f22012-07-12 09:43:27 +08009296 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009297 if (target) {
9298 point = xmlStrstr(str->stringval, find->stringval);
9299 if (point) {
9300 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009301 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009302 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009303 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009304 xmlBufContent(target)));
9305 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009306 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009307 xmlXPathReleaseObject(ctxt->context, str);
9308 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009309}
9310
9311/**
9312 * xmlXPathSubstringAfterFunction:
9313 * @ctxt: the XPath Parser context
9314 * @nargs: the number of arguments
9315 *
9316 * Implement the substring-after() XPath function
9317 * string substring-after(string, string)
9318 * The substring-after function returns the substring of the first
9319 * argument string that follows the first occurrence of the second
9320 * argument string in the first argument string, or the empty stringi
9321 * if the first argument string does not contain the second argument
9322 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9323 * and substring-after("1999/04/01","19") returns 99/04/01.
9324 */
9325void
9326xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9327 xmlXPathObjectPtr str;
9328 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009329 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009330 const xmlChar *point;
9331 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009332
Owen Taylor3473f882001-02-23 17:55:21 +00009333 CHECK_ARITY(2);
9334 CAST_TO_STRING;
9335 find = valuePop(ctxt);
9336 CAST_TO_STRING;
9337 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009338
Daniel Veillardade10f22012-07-12 09:43:27 +08009339 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009340 if (target) {
9341 point = xmlStrstr(str->stringval, find->stringval);
9342 if (point) {
9343 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009344 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009345 xmlStrlen(str->stringval) - offset);
9346 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009347 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009348 xmlBufContent(target)));
9349 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009350 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009351 xmlXPathReleaseObject(ctxt->context, str);
9352 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009353}
9354
9355/**
9356 * xmlXPathNormalizeFunction:
9357 * @ctxt: the XPath Parser context
9358 * @nargs: the number of arguments
9359 *
9360 * Implement the normalize-space() XPath function
9361 * string normalize-space(string?)
9362 * The normalize-space function returns the argument string with white
9363 * space normalized by stripping leading and trailing whitespace
9364 * and replacing sequences of whitespace characters by a single
9365 * space. Whitespace characters are the same allowed by the S production
9366 * in XML. If the argument is omitted, it defaults to the context
9367 * node converted to a string, in other words the value of the context node.
9368 */
9369void
9370xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9371 xmlXPathObjectPtr obj = NULL;
9372 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009373 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009374 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009375
Daniel Veillarda82b1822004-11-08 16:24:57 +00009376 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009377 if (nargs == 0) {
9378 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009379 valuePush(ctxt,
9380 xmlXPathCacheWrapString(ctxt->context,
9381 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009382 nargs = 1;
9383 }
9384
9385 CHECK_ARITY(1);
9386 CAST_TO_STRING;
9387 CHECK_TYPE(XPATH_STRING);
9388 obj = valuePop(ctxt);
9389 source = obj->stringval;
9390
Daniel Veillardade10f22012-07-12 09:43:27 +08009391 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009392 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009393
Owen Taylor3473f882001-02-23 17:55:21 +00009394 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009395 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009396 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009397
Owen Taylor3473f882001-02-23 17:55:21 +00009398 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9399 blank = 0;
9400 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009401 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009402 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009403 } else {
9404 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009405 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009406 blank = 0;
9407 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009408 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009409 }
9410 source++;
9411 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009412 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009413 xmlBufContent(target)));
9414 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009415 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009416 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009417}
9418
9419/**
9420 * xmlXPathTranslateFunction:
9421 * @ctxt: the XPath Parser context
9422 * @nargs: the number of arguments
9423 *
9424 * Implement the translate() XPath function
9425 * string translate(string, string, string)
9426 * The translate function returns the first argument string with
9427 * occurrences of characters in the second argument string replaced
9428 * by the character at the corresponding position in the third argument
9429 * string. For example, translate("bar","abc","ABC") returns the string
9430 * BAr. If there is a character in the second argument string with no
9431 * character at a corresponding position in the third argument string
9432 * (because the second argument string is longer than the third argument
9433 * string), then occurrences of that character in the first argument
9434 * string are removed. For example, translate("--aaa--","abc-","ABC")
9435 * returns "AAA". If a character occurs more than once in second
9436 * argument string, then the first occurrence determines the replacement
9437 * character. If the third argument string is longer than the second
9438 * argument string, then excess characters are ignored.
9439 */
9440void
9441xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009442 xmlXPathObjectPtr str;
9443 xmlXPathObjectPtr from;
9444 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009445 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009446 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009447 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009448 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009449 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009450
Daniel Veillarde043ee12001-04-16 14:08:07 +00009451 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009452
Daniel Veillarde043ee12001-04-16 14:08:07 +00009453 CAST_TO_STRING;
9454 to = valuePop(ctxt);
9455 CAST_TO_STRING;
9456 from = valuePop(ctxt);
9457 CAST_TO_STRING;
9458 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009459
Daniel Veillardade10f22012-07-12 09:43:27 +08009460 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009461 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009462 max = xmlUTF8Strlen(to->stringval);
9463 for (cptr = str->stringval; (ch=*cptr); ) {
9464 offset = xmlUTF8Strloc(from->stringval, cptr);
9465 if (offset >= 0) {
9466 if (offset < max) {
9467 point = xmlUTF8Strpos(to->stringval, offset);
9468 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009469 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009470 }
9471 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009472 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009473
9474 /* Step to next character in input */
9475 cptr++;
9476 if ( ch & 0x80 ) {
9477 /* if not simple ascii, verify proper format */
9478 if ( (ch & 0xc0) != 0xc0 ) {
9479 xmlGenericError(xmlGenericErrorContext,
9480 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009481 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009482 break;
9483 }
9484 /* then skip over remaining bytes for this char */
9485 while ( (ch <<= 1) & 0x80 )
9486 if ( (*cptr++ & 0xc0) != 0x80 ) {
9487 xmlGenericError(xmlGenericErrorContext,
9488 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009489 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009490 break;
9491 }
9492 if (ch & 0x80) /* must have had error encountered */
9493 break;
9494 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009495 }
Owen Taylor3473f882001-02-23 17:55:21 +00009496 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009497 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009498 xmlBufContent(target)));
9499 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009500 xmlXPathReleaseObject(ctxt->context, str);
9501 xmlXPathReleaseObject(ctxt->context, from);
9502 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009503}
9504
9505/**
9506 * xmlXPathBooleanFunction:
9507 * @ctxt: the XPath Parser context
9508 * @nargs: the number of arguments
9509 *
9510 * Implement the boolean() XPath function
9511 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009512 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009513 * - a number is true if and only if it is neither positive or
9514 * negative zero nor NaN
9515 * - a node-set is true if and only if it is non-empty
9516 * - a string is true if and only if its length is non-zero
9517 */
9518void
9519xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9520 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009521
9522 CHECK_ARITY(1);
9523 cur = valuePop(ctxt);
9524 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009525 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009526 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009527}
9528
9529/**
9530 * xmlXPathNotFunction:
9531 * @ctxt: the XPath Parser context
9532 * @nargs: the number of arguments
9533 *
9534 * Implement the not() XPath function
9535 * boolean not(boolean)
9536 * The not function returns true if its argument is false,
9537 * and false otherwise.
9538 */
9539void
9540xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9541 CHECK_ARITY(1);
9542 CAST_TO_BOOLEAN;
9543 CHECK_TYPE(XPATH_BOOLEAN);
9544 ctxt->value->boolval = ! ctxt->value->boolval;
9545}
9546
9547/**
9548 * xmlXPathTrueFunction:
9549 * @ctxt: the XPath Parser context
9550 * @nargs: the number of arguments
9551 *
9552 * Implement the true() XPath function
9553 * boolean true()
9554 */
9555void
9556xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9557 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009558 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009559}
9560
9561/**
9562 * xmlXPathFalseFunction:
9563 * @ctxt: the XPath Parser context
9564 * @nargs: the number of arguments
9565 *
9566 * Implement the false() XPath function
9567 * boolean false()
9568 */
9569void
9570xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9571 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009572 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009573}
9574
9575/**
9576 * xmlXPathLangFunction:
9577 * @ctxt: the XPath Parser context
9578 * @nargs: the number of arguments
9579 *
9580 * Implement the lang() XPath function
9581 * boolean lang(string)
9582 * The lang function returns true or false depending on whether the
9583 * language of the context node as specified by xml:lang attributes
9584 * is the same as or is a sublanguage of the language specified by
9585 * the argument string. The language of the context node is determined
9586 * by the value of the xml:lang attribute on the context node, or, if
9587 * the context node has no xml:lang attribute, by the value of the
9588 * xml:lang attribute on the nearest ancestor of the context node that
9589 * has an xml:lang attribute. If there is no such attribute, then lang
9590 * returns false. If there is such an attribute, then lang returns
9591 * true if the attribute value is equal to the argument ignoring case,
9592 * or if there is some suffix starting with - such that the attribute
9593 * value is equal to the argument ignoring that suffix of the attribute
9594 * value and ignoring case.
9595 */
9596void
9597xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009598 xmlXPathObjectPtr val = NULL;
9599 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009600 const xmlChar *lang;
9601 int ret = 0;
9602 int i;
9603
9604 CHECK_ARITY(1);
9605 CAST_TO_STRING;
9606 CHECK_TYPE(XPATH_STRING);
9607 val = valuePop(ctxt);
9608 lang = val->stringval;
9609 theLang = xmlNodeGetLang(ctxt->context->node);
9610 if ((theLang != NULL) && (lang != NULL)) {
9611 for (i = 0;lang[i] != 0;i++)
9612 if (toupper(lang[i]) != toupper(theLang[i]))
9613 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009614 if ((theLang[i] == 0) || (theLang[i] == '-'))
9615 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009616 }
9617not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009618 if (theLang != NULL)
9619 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009620
9621 xmlXPathReleaseObject(ctxt->context, val);
9622 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009623}
9624
9625/**
9626 * xmlXPathNumberFunction:
9627 * @ctxt: the XPath Parser context
9628 * @nargs: the number of arguments
9629 *
9630 * Implement the number() XPath function
9631 * number number(object?)
9632 */
9633void
9634xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9635 xmlXPathObjectPtr cur;
9636 double res;
9637
Daniel Veillarda82b1822004-11-08 16:24:57 +00009638 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009639 if (nargs == 0) {
9640 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009641 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009642 } else {
9643 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9644
9645 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009646 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009647 xmlFree(content);
9648 }
9649 return;
9650 }
9651
9652 CHECK_ARITY(1);
9653 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009654 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009655}
9656
9657/**
9658 * xmlXPathSumFunction:
9659 * @ctxt: the XPath Parser context
9660 * @nargs: the number of arguments
9661 *
9662 * Implement the sum() XPath function
9663 * number sum(node-set)
9664 * The sum function returns the sum of the values of the nodes in
9665 * the argument node-set.
9666 */
9667void
9668xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9669 xmlXPathObjectPtr cur;
9670 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009671 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009672
9673 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009674 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009675 ((ctxt->value->type != XPATH_NODESET) &&
9676 (ctxt->value->type != XPATH_XSLT_TREE)))
9677 XP_ERROR(XPATH_INVALID_TYPE);
9678 cur = valuePop(ctxt);
9679
William M. Brack08171912003-12-29 02:52:11 +00009680 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009681 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9682 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009683 }
9684 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009685 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9686 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009687}
9688
9689/**
9690 * xmlXPathFloorFunction:
9691 * @ctxt: the XPath Parser context
9692 * @nargs: the number of arguments
9693 *
9694 * Implement the floor() XPath function
9695 * number floor(number)
9696 * The floor function returns the largest (closest to positive infinity)
9697 * number that is not greater than the argument and that is an integer.
9698 */
9699void
9700xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9701 CHECK_ARITY(1);
9702 CAST_TO_NUMBER;
9703 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009704
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009705 ctxt->value->floatval = floor(ctxt->value->floatval);
Owen Taylor3473f882001-02-23 17:55:21 +00009706}
9707
9708/**
9709 * xmlXPathCeilingFunction:
9710 * @ctxt: the XPath Parser context
9711 * @nargs: the number of arguments
9712 *
9713 * Implement the ceiling() XPath function
9714 * number ceiling(number)
9715 * The ceiling function returns the smallest (closest to negative infinity)
9716 * number that is not less than the argument and that is an integer.
9717 */
9718void
9719xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Owen Taylor3473f882001-02-23 17:55:21 +00009720 CHECK_ARITY(1);
9721 CAST_TO_NUMBER;
9722 CHECK_TYPE(XPATH_NUMBER);
9723
Owen Taylor3473f882001-02-23 17:55:21 +00009724 ctxt->value->floatval = ceil(ctxt->value->floatval);
Owen Taylor3473f882001-02-23 17:55:21 +00009725}
9726
9727/**
9728 * xmlXPathRoundFunction:
9729 * @ctxt: the XPath Parser context
9730 * @nargs: the number of arguments
9731 *
9732 * Implement the round() XPath function
9733 * number round(number)
9734 * The round function returns the number that is closest to the
9735 * argument and that is an integer. If there are two such numbers,
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009736 * then the one that is closest to positive infinity is returned.
Owen Taylor3473f882001-02-23 17:55:21 +00009737 */
9738void
9739xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9740 double f;
9741
9742 CHECK_ARITY(1);
9743 CAST_TO_NUMBER;
9744 CHECK_TYPE(XPATH_NUMBER);
9745
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009746 f = ctxt->value->floatval;
9747
9748 /* Test for zero to keep negative zero unchanged. */
9749 if ((xmlXPathIsNaN(f)) || (f == 0.0))
Owen Taylor3473f882001-02-23 17:55:21 +00009750 return;
9751
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009752 if ((f >= -0.5) && (f < 0.0)) {
9753 /* Negative zero. */
9754 ctxt->value->floatval = xmlXPathNZERO;
9755 }
9756 else {
9757 double rounded = floor(f);
9758 if (f - rounded >= 0.5)
9759 rounded += 1.0;
9760 ctxt->value->floatval = rounded;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009761 }
Owen Taylor3473f882001-02-23 17:55:21 +00009762}
9763
9764/************************************************************************
9765 * *
9766 * The Parser *
9767 * *
9768 ************************************************************************/
9769
9770/*
William M. Brack08171912003-12-29 02:52:11 +00009771 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009772 * implementation.
9773 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009774static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009775static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009776static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009777static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009778static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9779 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009780
9781/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009782 * xmlXPathCurrentChar:
9783 * @ctxt: the XPath parser context
9784 * @cur: pointer to the beginning of the char
9785 * @len: pointer to the length of the char read
9786 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009787 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009788 * bytes in the input buffer.
9789 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009790 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009791 */
9792
9793static int
9794xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9795 unsigned char c;
9796 unsigned int val;
9797 const xmlChar *cur;
9798
9799 if (ctxt == NULL)
9800 return(0);
9801 cur = ctxt->cur;
9802
9803 /*
9804 * We are supposed to handle UTF8, check it's valid
9805 * From rfc2044: encoding of the Unicode values on UTF-8:
9806 *
9807 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9808 * 0000 0000-0000 007F 0xxxxxxx
9809 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009810 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009811 *
9812 * Check for the 0x110000 limit too
9813 */
9814 c = *cur;
9815 if (c & 0x80) {
9816 if ((cur[1] & 0xc0) != 0x80)
9817 goto encoding_error;
9818 if ((c & 0xe0) == 0xe0) {
9819
9820 if ((cur[2] & 0xc0) != 0x80)
9821 goto encoding_error;
9822 if ((c & 0xf0) == 0xf0) {
9823 if (((c & 0xf8) != 0xf0) ||
9824 ((cur[3] & 0xc0) != 0x80))
9825 goto encoding_error;
9826 /* 4-byte code */
9827 *len = 4;
9828 val = (cur[0] & 0x7) << 18;
9829 val |= (cur[1] & 0x3f) << 12;
9830 val |= (cur[2] & 0x3f) << 6;
9831 val |= cur[3] & 0x3f;
9832 } else {
9833 /* 3-byte code */
9834 *len = 3;
9835 val = (cur[0] & 0xf) << 12;
9836 val |= (cur[1] & 0x3f) << 6;
9837 val |= cur[2] & 0x3f;
9838 }
9839 } else {
9840 /* 2-byte code */
9841 *len = 2;
9842 val = (cur[0] & 0x1f) << 6;
9843 val |= cur[1] & 0x3f;
9844 }
9845 if (!IS_CHAR(val)) {
9846 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009847 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009848 return(val);
9849 } else {
9850 /* 1-byte code */
9851 *len = 1;
9852 return((int) *cur);
9853 }
9854encoding_error:
9855 /*
William M. Brack08171912003-12-29 02:52:11 +00009856 * If we detect an UTF8 error that probably means that the
9857 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009858 * declaration header. Report the error and switch the encoding
9859 * to ISO-Latin-1 (if you don't like this policy, just declare the
9860 * encoding !)
9861 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009862 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009863 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009864}
9865
9866/**
Owen Taylor3473f882001-02-23 17:55:21 +00009867 * xmlXPathParseNCName:
9868 * @ctxt: the XPath Parser context
9869 *
9870 * parse an XML namespace non qualified name.
9871 *
9872 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9873 *
9874 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9875 * CombiningChar | Extender
9876 *
9877 * Returns the namespace name or NULL
9878 */
9879
9880xmlChar *
9881xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009882 const xmlChar *in;
9883 xmlChar *ret;
9884 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009885
Daniel Veillarda82b1822004-11-08 16:24:57 +00009886 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009887 /*
9888 * Accelerator for simple ASCII names
9889 */
9890 in = ctxt->cur;
9891 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9892 ((*in >= 0x41) && (*in <= 0x5A)) ||
9893 (*in == '_')) {
9894 in++;
9895 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9896 ((*in >= 0x41) && (*in <= 0x5A)) ||
9897 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009898 (*in == '_') || (*in == '.') ||
9899 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009900 in++;
9901 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9902 (*in == '[') || (*in == ']') || (*in == ':') ||
9903 (*in == '@') || (*in == '*')) {
9904 count = in - ctxt->cur;
9905 if (count == 0)
9906 return(NULL);
9907 ret = xmlStrndup(ctxt->cur, count);
9908 ctxt->cur = in;
9909 return(ret);
9910 }
9911 }
9912 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009913}
9914
Daniel Veillard2156a562001-04-28 12:24:34 +00009915
Owen Taylor3473f882001-02-23 17:55:21 +00009916/**
9917 * xmlXPathParseQName:
9918 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009919 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009920 *
9921 * parse an XML qualified name
9922 *
9923 * [NS 5] QName ::= (Prefix ':')? LocalPart
9924 *
9925 * [NS 6] Prefix ::= NCName
9926 *
9927 * [NS 7] LocalPart ::= NCName
9928 *
9929 * Returns the function returns the local part, and prefix is updated
9930 * to get the Prefix if any.
9931 */
9932
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009933static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009934xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9935 xmlChar *ret = NULL;
9936
9937 *prefix = NULL;
9938 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009939 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009940 *prefix = ret;
9941 NEXT;
9942 ret = xmlXPathParseNCName(ctxt);
9943 }
9944 return(ret);
9945}
9946
9947/**
9948 * xmlXPathParseName:
9949 * @ctxt: the XPath Parser context
9950 *
9951 * parse an XML name
9952 *
9953 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9954 * CombiningChar | Extender
9955 *
9956 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9957 *
9958 * Returns the namespace name or NULL
9959 */
9960
9961xmlChar *
9962xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009963 const xmlChar *in;
9964 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009965 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009966
Daniel Veillarda82b1822004-11-08 16:24:57 +00009967 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009968 /*
9969 * Accelerator for simple ASCII names
9970 */
9971 in = ctxt->cur;
9972 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9973 ((*in >= 0x41) && (*in <= 0x5A)) ||
9974 (*in == '_') || (*in == ':')) {
9975 in++;
9976 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9977 ((*in >= 0x41) && (*in <= 0x5A)) ||
9978 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009979 (*in == '_') || (*in == '-') ||
9980 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009981 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009982 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009983 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009984 if (count > XML_MAX_NAME_LENGTH) {
9985 ctxt->cur = in;
9986 XP_ERRORNULL(XPATH_EXPR_ERROR);
9987 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009988 ret = xmlStrndup(ctxt->cur, count);
9989 ctxt->cur = in;
9990 return(ret);
9991 }
9992 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009993 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009994}
9995
Daniel Veillard61d80a22001-04-27 17:13:01 +00009996static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009997xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009998 xmlChar buf[XML_MAX_NAMELEN + 5];
9999 int len = 0, l;
10000 int c;
10001
10002 /*
10003 * Handler for more complex cases
10004 */
10005 c = CUR_CHAR(l);
10006 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +000010007 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
10008 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +000010009 (!IS_LETTER(c) && (c != '_') &&
Nick Wellnhofere2893902016-04-21 19:19:23 +020010010 ((!qualified) || (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +000010011 return(NULL);
10012 }
10013
10014 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10015 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10016 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010017 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +000010018 (IS_COMBINING(c)) ||
10019 (IS_EXTENDER(c)))) {
10020 COPY_BUF(l,buf,len,c);
10021 NEXTL(l);
10022 c = CUR_CHAR(l);
10023 if (len >= XML_MAX_NAMELEN) {
10024 /*
10025 * Okay someone managed to make a huge name, so he's ready to pay
10026 * for the processing speed.
10027 */
10028 xmlChar *buffer;
10029 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010030
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010031 if (len > XML_MAX_NAME_LENGTH) {
10032 XP_ERRORNULL(XPATH_EXPR_ERROR);
10033 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +000010034 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010035 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010036 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010037 }
10038 memcpy(buffer, buf, len);
10039 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10040 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010041 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +000010042 (IS_COMBINING(c)) ||
10043 (IS_EXTENDER(c))) {
10044 if (len + 10 > max) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010045 if (max > XML_MAX_NAME_LENGTH) {
10046 XP_ERRORNULL(XPATH_EXPR_ERROR);
10047 }
Daniel Veillard61d80a22001-04-27 17:13:01 +000010048 max *= 2;
10049 buffer = (xmlChar *) xmlRealloc(buffer,
10050 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010051 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010052 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010053 }
10054 }
10055 COPY_BUF(l,buffer,len,c);
10056 NEXTL(l);
10057 c = CUR_CHAR(l);
10058 }
10059 buffer[len] = 0;
10060 return(buffer);
10061 }
10062 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010063 if (len == 0)
10064 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010065 return(xmlStrndup(buf, len));
10066}
Daniel Veillard3cd72402002-05-13 10:33:30 +000010067
10068#define MAX_FRAC 20
10069
Owen Taylor3473f882001-02-23 17:55:21 +000010070/**
10071 * xmlXPathStringEvalNumber:
10072 * @str: A string to scan
10073 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000010074 * [30a] Float ::= Number ('e' Digits?)?
10075 *
Owen Taylor3473f882001-02-23 17:55:21 +000010076 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010077 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010078 * [31] Digits ::= [0-9]+
10079 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010080 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +000010081 * In complement of the Number expression, this function also handles
10082 * negative values : '-' Number.
10083 *
10084 * Returns the double value.
10085 */
10086double
10087xmlXPathStringEvalNumber(const xmlChar *str) {
10088 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +000010089 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010090 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010091 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010092 int exponent = 0;
10093 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010094#ifdef __GNUC__
10095 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010096 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010097#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010098 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +000010099 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010100 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10101 return(xmlXPathNAN);
10102 }
10103 if (*cur == '-') {
10104 isneg = 1;
10105 cur++;
10106 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010107
10108#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010109 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010110 * tmp/temp is a workaround against a gcc compiler bug
10111 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010112 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010113 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010114 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010115 ret = ret * 10;
10116 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010117 ok = 1;
10118 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010119 temp = (double) tmp;
10120 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010121 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010122#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010123 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010124 while ((*cur >= '0') && (*cur <= '9')) {
10125 ret = ret * 10 + (*cur - '0');
10126 ok = 1;
10127 cur++;
10128 }
10129#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010130
Owen Taylor3473f882001-02-23 17:55:21 +000010131 if (*cur == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010132 int v, frac = 0, max;
Daniel Veillard3cd72402002-05-13 10:33:30 +000010133 double fraction = 0;
10134
Owen Taylor3473f882001-02-23 17:55:21 +000010135 cur++;
10136 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10137 return(xmlXPathNAN);
10138 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010139 while (*cur == '0') {
10140 frac = frac + 1;
10141 cur++;
10142 }
10143 max = frac + MAX_FRAC;
10144 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010145 v = (*cur - '0');
10146 fraction = fraction * 10 + v;
10147 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010148 cur++;
10149 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010150 fraction /= pow(10.0, frac);
Daniel Veillard3cd72402002-05-13 10:33:30 +000010151 ret = ret + fraction;
10152 while ((*cur >= '0') && (*cur <= '9'))
10153 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010154 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010155 if ((*cur == 'e') || (*cur == 'E')) {
10156 cur++;
10157 if (*cur == '-') {
10158 is_exponent_negative = 1;
10159 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010160 } else if (*cur == '+') {
10161 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010162 }
10163 while ((*cur >= '0') && (*cur <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010164 if (exponent < 1000000)
10165 exponent = exponent * 10 + (*cur - '0');
Bjorn Reese70a9da52001-04-21 16:57:29 +000010166 cur++;
10167 }
10168 }
William M. Brack76e95df2003-10-18 16:20:14 +000010169 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010170 if (*cur != 0) return(xmlXPathNAN);
10171 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010172 if (is_exponent_negative) exponent = -exponent;
10173 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010174 return(ret);
10175}
10176
10177/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010178 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010179 * @ctxt: the XPath Parser context
10180 *
10181 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010182 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010183 * [31] Digits ::= [0-9]+
10184 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010185 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010186 *
10187 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010188static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010189xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10190{
Owen Taylor3473f882001-02-23 17:55:21 +000010191 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010192 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010193 int exponent = 0;
10194 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010195#ifdef __GNUC__
10196 unsigned long tmp = 0;
10197 double temp;
10198#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010199
10200 CHECK_ERROR;
10201 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10202 XP_ERROR(XPATH_NUMBER_ERROR);
10203 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010204#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010205 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010206 * tmp/temp is a workaround against a gcc compiler bug
10207 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010208 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010209 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010210 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010211 ret = ret * 10;
10212 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010213 ok = 1;
10214 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010215 temp = (double) tmp;
10216 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010217 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010218#else
10219 ret = 0;
10220 while ((CUR >= '0') && (CUR <= '9')) {
10221 ret = ret * 10 + (CUR - '0');
10222 ok = 1;
10223 NEXT;
10224 }
10225#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010226 if (CUR == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010227 int v, frac = 0, max;
Phil Shaferee32ad32010-11-03 20:53:55 +010010228 double fraction = 0;
10229
Owen Taylor3473f882001-02-23 17:55:21 +000010230 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010231 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10232 XP_ERROR(XPATH_NUMBER_ERROR);
10233 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010234 while (CUR == '0') {
10235 frac = frac + 1;
10236 NEXT;
10237 }
10238 max = frac + MAX_FRAC;
10239 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
Phil Shaferee32ad32010-11-03 20:53:55 +010010240 v = (CUR - '0');
10241 fraction = fraction * 10 + v;
10242 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010243 NEXT;
10244 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010245 fraction /= pow(10.0, frac);
Phil Shaferee32ad32010-11-03 20:53:55 +010010246 ret = ret + fraction;
10247 while ((CUR >= '0') && (CUR <= '9'))
10248 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010249 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010250 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010251 NEXT;
10252 if (CUR == '-') {
10253 is_exponent_negative = 1;
10254 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010255 } else if (CUR == '+') {
10256 NEXT;
10257 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010258 while ((CUR >= '0') && (CUR <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010259 if (exponent < 1000000)
10260 exponent = exponent * 10 + (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010261 NEXT;
10262 }
10263 if (is_exponent_negative)
10264 exponent = -exponent;
10265 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010266 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010267 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010268 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010269}
10270
10271/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010272 * xmlXPathParseLiteral:
10273 * @ctxt: the XPath Parser context
10274 *
10275 * Parse a Literal
10276 *
10277 * [29] Literal ::= '"' [^"]* '"'
10278 * | "'" [^']* "'"
10279 *
10280 * Returns the value found or NULL in case of error
10281 */
10282static xmlChar *
10283xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10284 const xmlChar *q;
10285 xmlChar *ret = NULL;
10286
10287 if (CUR == '"') {
10288 NEXT;
10289 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010290 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010291 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010292 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010293 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010294 } else {
10295 ret = xmlStrndup(q, CUR_PTR - q);
10296 NEXT;
10297 }
10298 } else if (CUR == '\'') {
10299 NEXT;
10300 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010301 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010302 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010303 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010304 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010305 } else {
10306 ret = xmlStrndup(q, CUR_PTR - q);
10307 NEXT;
10308 }
10309 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010310 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010311 }
10312 return(ret);
10313}
10314
10315/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010316 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010317 * @ctxt: the XPath Parser context
10318 *
10319 * Parse a Literal and push it on the stack.
10320 *
10321 * [29] Literal ::= '"' [^"]* '"'
10322 * | "'" [^']* "'"
10323 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010324 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010325 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010326static void
10327xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010328 const xmlChar *q;
10329 xmlChar *ret = NULL;
10330
10331 if (CUR == '"') {
10332 NEXT;
10333 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010334 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010335 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010336 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010337 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10338 } else {
10339 ret = xmlStrndup(q, CUR_PTR - q);
10340 NEXT;
10341 }
10342 } else if (CUR == '\'') {
10343 NEXT;
10344 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010345 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010346 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010347 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010348 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10349 } else {
10350 ret = xmlStrndup(q, CUR_PTR - q);
10351 NEXT;
10352 }
10353 } else {
10354 XP_ERROR(XPATH_START_LITERAL_ERROR);
10355 }
10356 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010357 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010358 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010359 xmlFree(ret);
10360}
10361
10362/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010363 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010364 * @ctxt: the XPath Parser context
10365 *
10366 * Parse a VariableReference, evaluate it and push it on the stack.
10367 *
10368 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010369 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010370 * of any of the types that are possible for the value of an expression,
10371 * and may also be of additional types not specified here.
10372 *
10373 * Early evaluation is possible since:
10374 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010375 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010376 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010377 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010378 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010379static void
10380xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010381 xmlChar *name;
10382 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010383
10384 SKIP_BLANKS;
10385 if (CUR != '$') {
10386 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10387 }
10388 NEXT;
10389 name = xmlXPathParseQName(ctxt, &prefix);
10390 if (name == NULL) {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010391 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010392 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10393 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010394 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010395 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10396 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010397 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010398 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
Daniel Veillard47881282012-09-07 14:24:50 +080010399 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
Daniel Veillardb3d14912005-09-04 20:47:39 +000010400 }
Owen Taylor3473f882001-02-23 17:55:21 +000010401}
10402
10403/**
10404 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010405 * @name: a name string
10406 *
10407 * Is the name given a NodeType one.
10408 *
10409 * [38] NodeType ::= 'comment'
10410 * | 'text'
10411 * | 'processing-instruction'
10412 * | 'node'
10413 *
10414 * Returns 1 if true 0 otherwise
10415 */
10416int
10417xmlXPathIsNodeType(const xmlChar *name) {
10418 if (name == NULL)
10419 return(0);
10420
Daniel Veillard1971ee22002-01-31 20:29:19 +000010421 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010422 return(1);
10423 if (xmlStrEqual(name, BAD_CAST "text"))
10424 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010425 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010426 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010427 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010428 return(1);
10429 return(0);
10430}
10431
10432/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010433 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010434 * @ctxt: the XPath Parser context
10435 *
10436 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010437 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010438 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010439 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010440 * pushed on the stack
10441 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010442static void
10443xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010444 xmlChar *name;
10445 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010446 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010447 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010448
10449 name = xmlXPathParseQName(ctxt, &prefix);
10450 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010451 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010452 XP_ERROR(XPATH_EXPR_ERROR);
10453 }
10454 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010455#ifdef DEBUG_EXPR
10456 if (prefix == NULL)
10457 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10458 name);
10459 else
10460 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10461 prefix, name);
10462#endif
10463
Owen Taylor3473f882001-02-23 17:55:21 +000010464 if (CUR != '(') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010465 xmlFree(name);
10466 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010467 XP_ERROR(XPATH_EXPR_ERROR);
10468 }
10469 NEXT;
10470 SKIP_BLANKS;
10471
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010472 /*
10473 * Optimization for count(): we don't need the node-set to be sorted.
10474 */
10475 if ((prefix == NULL) && (name[0] == 'c') &&
10476 xmlStrEqual(name, BAD_CAST "count"))
10477 {
10478 sort = 0;
10479 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010480 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010481 if (CUR != ')') {
10482 while (CUR != 0) {
10483 int op1 = ctxt->comp->last;
10484 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010485 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010486 if (ctxt->error != XPATH_EXPRESSION_OK) {
10487 xmlFree(name);
10488 xmlFree(prefix);
10489 return;
10490 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010491 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10492 nbargs++;
10493 if (CUR == ')') break;
10494 if (CUR != ',') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010495 xmlFree(name);
10496 xmlFree(prefix);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010497 XP_ERROR(XPATH_EXPR_ERROR);
10498 }
10499 NEXT;
10500 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010501 }
Owen Taylor3473f882001-02-23 17:55:21 +000010502 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010503 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10504 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010505 NEXT;
10506 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010507}
10508
10509/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010510 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010511 * @ctxt: the XPath Parser context
10512 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010513 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010514 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010515 * | Literal
10516 * | Number
10517 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010518 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010519 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010520 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010521static void
10522xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010523 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010524 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010525 else if (CUR == '(') {
10526 NEXT;
10527 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010528 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010529 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010530 if (CUR != ')') {
10531 XP_ERROR(XPATH_EXPR_ERROR);
10532 }
10533 NEXT;
10534 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010535 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010536 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010537 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010538 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010539 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010540 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010541 }
10542 SKIP_BLANKS;
10543}
10544
10545/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010546 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010547 * @ctxt: the XPath Parser context
10548 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010549 * [20] FilterExpr ::= PrimaryExpr
10550 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010551 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010552 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010553 * Square brackets are used to filter expressions in the same way that
10554 * they are used in location paths. It is an error if the expression to
10555 * be filtered does not evaluate to a node-set. The context node list
10556 * used for evaluating the expression in square brackets is the node-set
10557 * to be filtered listed in document order.
10558 */
10559
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010560static void
10561xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10562 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010563 CHECK_ERROR;
10564 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010565
Owen Taylor3473f882001-02-23 17:55:21 +000010566 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010567 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010568 SKIP_BLANKS;
10569 }
10570
Daniel Veillard45490ae2008-07-29 09:13:19 +000010571
Owen Taylor3473f882001-02-23 17:55:21 +000010572}
10573
10574/**
10575 * xmlXPathScanName:
10576 * @ctxt: the XPath Parser context
10577 *
10578 * Trickery: parse an XML name but without consuming the input flow
10579 * Needed to avoid insanity in the parser state.
10580 *
10581 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10582 * CombiningChar | Extender
10583 *
10584 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10585 *
10586 * [6] Names ::= Name (S Name)*
10587 *
10588 * Returns the Name parsed or NULL
10589 */
10590
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010591static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010592xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010593 int len = 0, l;
10594 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010595 const xmlChar *cur;
10596 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010597
Daniel Veillard03226812004-11-01 14:55:21 +000010598 cur = ctxt->cur;
10599
10600 c = CUR_CHAR(l);
10601 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10602 (!IS_LETTER(c) && (c != '_') &&
10603 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010604 return(NULL);
10605 }
10606
Daniel Veillard03226812004-11-01 14:55:21 +000010607 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10608 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10609 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010610 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010611 (IS_COMBINING(c)) ||
10612 (IS_EXTENDER(c)))) {
10613 len += l;
10614 NEXTL(l);
10615 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010616 }
Daniel Veillard03226812004-11-01 14:55:21 +000010617 ret = xmlStrndup(cur, ctxt->cur - cur);
10618 ctxt->cur = cur;
10619 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010620}
10621
10622/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010623 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010624 * @ctxt: the XPath Parser context
10625 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010626 * [19] PathExpr ::= LocationPath
10627 * | FilterExpr
10628 * | FilterExpr '/' RelativeLocationPath
10629 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010630 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010631 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010632 * The / operator and // operators combine an arbitrary expression
10633 * and a relative location path. It is an error if the expression
10634 * does not evaluate to a node-set.
10635 * The / operator does composition in the same way as when / is
10636 * used in a location path. As in location paths, // is short for
10637 * /descendant-or-self::node()/.
10638 */
10639
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010640static void
10641xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010642 int lc = 1; /* Should we branch to LocationPath ? */
10643 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10644
10645 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010646 if ((CUR == '$') || (CUR == '(') ||
10647 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010648 (CUR == '\'') || (CUR == '"') ||
10649 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010650 lc = 0;
10651 } else if (CUR == '*') {
10652 /* relative or absolute location path */
10653 lc = 1;
10654 } else if (CUR == '/') {
10655 /* relative or absolute location path */
10656 lc = 1;
10657 } else if (CUR == '@') {
10658 /* relative abbreviated attribute location path */
10659 lc = 1;
10660 } else if (CUR == '.') {
10661 /* relative abbreviated attribute location path */
10662 lc = 1;
10663 } else {
10664 /*
10665 * Problem is finding if we have a name here whether it's:
10666 * - a nodetype
10667 * - a function call in which case it's followed by '('
10668 * - an axis in which case it's followed by ':'
10669 * - a element name
10670 * We do an a priori analysis here rather than having to
10671 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010672 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010673 * read/write/debug.
10674 */
10675 SKIP_BLANKS;
10676 name = xmlXPathScanName(ctxt);
10677 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10678#ifdef DEBUG_STEP
10679 xmlGenericError(xmlGenericErrorContext,
10680 "PathExpr: Axis\n");
10681#endif
10682 lc = 1;
10683 xmlFree(name);
10684 } else if (name != NULL) {
10685 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010686
Daniel Veillard45490ae2008-07-29 09:13:19 +000010687
Owen Taylor3473f882001-02-23 17:55:21 +000010688 while (NXT(len) != 0) {
10689 if (NXT(len) == '/') {
10690 /* element name */
10691#ifdef DEBUG_STEP
10692 xmlGenericError(xmlGenericErrorContext,
10693 "PathExpr: AbbrRelLocation\n");
10694#endif
10695 lc = 1;
10696 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010697 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010698 /* ignore blanks */
10699 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010700 } else if (NXT(len) == ':') {
10701#ifdef DEBUG_STEP
10702 xmlGenericError(xmlGenericErrorContext,
10703 "PathExpr: AbbrRelLocation\n");
10704#endif
10705 lc = 1;
10706 break;
10707 } else if ((NXT(len) == '(')) {
Nick Wellnhofer9ab01a22016-06-28 14:22:23 +020010708 /* Node Type or Function */
Owen Taylor3473f882001-02-23 17:55:21 +000010709 if (xmlXPathIsNodeType(name)) {
10710#ifdef DEBUG_STEP
10711 xmlGenericError(xmlGenericErrorContext,
10712 "PathExpr: Type search\n");
10713#endif
10714 lc = 1;
Nick Wellnhofer9ab01a22016-06-28 14:22:23 +020010715#ifdef LIBXML_XPTR_ENABLED
10716 } else if (ctxt->xptr &&
10717 xmlStrEqual(name, BAD_CAST "range-to")) {
10718 lc = 1;
10719#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010720 } else {
10721#ifdef DEBUG_STEP
10722 xmlGenericError(xmlGenericErrorContext,
10723 "PathExpr: function call\n");
10724#endif
10725 lc = 0;
10726 }
10727 break;
10728 } else if ((NXT(len) == '[')) {
10729 /* element name */
10730#ifdef DEBUG_STEP
10731 xmlGenericError(xmlGenericErrorContext,
10732 "PathExpr: AbbrRelLocation\n");
10733#endif
10734 lc = 1;
10735 break;
10736 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10737 (NXT(len) == '=')) {
10738 lc = 1;
10739 break;
10740 } else {
10741 lc = 1;
10742 break;
10743 }
10744 len++;
10745 }
10746 if (NXT(len) == 0) {
10747#ifdef DEBUG_STEP
10748 xmlGenericError(xmlGenericErrorContext,
10749 "PathExpr: AbbrRelLocation\n");
10750#endif
10751 /* element name */
10752 lc = 1;
10753 }
10754 xmlFree(name);
10755 } else {
William M. Brack08171912003-12-29 02:52:11 +000010756 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010757 XP_ERROR(XPATH_EXPR_ERROR);
10758 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010759 }
Owen Taylor3473f882001-02-23 17:55:21 +000010760
10761 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010762 if (CUR == '/') {
10763 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10764 } else {
10765 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010766 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010767 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010768 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010769 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010770 CHECK_ERROR;
10771 if ((CUR == '/') && (NXT(1) == '/')) {
10772 SKIP(2);
10773 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010774
10775 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10776 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10777 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10778
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010779 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010780 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010781 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010782 }
10783 }
10784 SKIP_BLANKS;
10785}
10786
10787/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010788 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010789 * @ctxt: the XPath Parser context
10790 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010791 * [18] UnionExpr ::= PathExpr
10792 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010793 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010794 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010795 */
10796
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010797static void
10798xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10799 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010800 CHECK_ERROR;
10801 SKIP_BLANKS;
10802 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010803 int op1 = ctxt->comp->last;
10804 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010805
10806 NEXT;
10807 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010808 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010809
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010810 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10811
Owen Taylor3473f882001-02-23 17:55:21 +000010812 SKIP_BLANKS;
10813 }
Owen Taylor3473f882001-02-23 17:55:21 +000010814}
10815
10816/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010817 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010818 * @ctxt: the XPath Parser context
10819 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010820 * [27] UnaryExpr ::= UnionExpr
10821 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010822 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010823 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010824 */
10825
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010826static void
10827xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010828 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010829 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010830
10831 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010832 while (CUR == '-') {
10833 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010834 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010835 NEXT;
10836 SKIP_BLANKS;
10837 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010838
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010839 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010840 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010841 if (found) {
10842 if (minus)
10843 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10844 else
10845 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010846 }
10847}
10848
10849/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010850 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010851 * @ctxt: the XPath Parser context
10852 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010853 * [26] MultiplicativeExpr ::= UnaryExpr
10854 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10855 * | MultiplicativeExpr 'div' UnaryExpr
10856 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010857 * [34] MultiplyOperator ::= '*'
10858 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010859 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010860 */
10861
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010862static void
10863xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10864 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010865 CHECK_ERROR;
10866 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010867 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010868 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10869 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10870 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010871 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010872
10873 if (CUR == '*') {
10874 op = 0;
10875 NEXT;
10876 } else if (CUR == 'd') {
10877 op = 1;
10878 SKIP(3);
10879 } else if (CUR == 'm') {
10880 op = 2;
10881 SKIP(3);
10882 }
10883 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010884 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010885 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010886 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010887 SKIP_BLANKS;
10888 }
10889}
10890
10891/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010892 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010893 * @ctxt: the XPath Parser context
10894 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010895 * [25] AdditiveExpr ::= MultiplicativeExpr
10896 * | AdditiveExpr '+' MultiplicativeExpr
10897 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010898 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010899 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010900 */
10901
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010902static void
10903xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010904
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010905 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010906 CHECK_ERROR;
10907 SKIP_BLANKS;
10908 while ((CUR == '+') || (CUR == '-')) {
10909 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010910 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010911
10912 if (CUR == '+') plus = 1;
10913 else plus = 0;
10914 NEXT;
10915 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010916 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010917 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010918 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010919 SKIP_BLANKS;
10920 }
10921}
10922
10923/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010924 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010925 * @ctxt: the XPath Parser context
10926 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010927 * [24] RelationalExpr ::= AdditiveExpr
10928 * | RelationalExpr '<' AdditiveExpr
10929 * | RelationalExpr '>' AdditiveExpr
10930 * | RelationalExpr '<=' AdditiveExpr
10931 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010932 *
10933 * A <= B > C is allowed ? Answer from James, yes with
10934 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10935 * which is basically what got implemented.
10936 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010937 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010938 * on the stack
10939 */
10940
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010941static void
10942xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10943 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010944 CHECK_ERROR;
10945 SKIP_BLANKS;
10946 while ((CUR == '<') ||
10947 (CUR == '>') ||
10948 ((CUR == '<') && (NXT(1) == '=')) ||
10949 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010950 int inf, strict;
10951 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010952
10953 if (CUR == '<') inf = 1;
10954 else inf = 0;
10955 if (NXT(1) == '=') strict = 0;
10956 else strict = 1;
10957 NEXT;
10958 if (!strict) NEXT;
10959 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010960 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010961 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010962 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010963 SKIP_BLANKS;
10964 }
10965}
10966
10967/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010968 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010969 * @ctxt: the XPath Parser context
10970 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010971 * [23] EqualityExpr ::= RelationalExpr
10972 * | EqualityExpr '=' RelationalExpr
10973 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010974 *
10975 * A != B != C is allowed ? Answer from James, yes with
10976 * (RelationalExpr = RelationalExpr) = RelationalExpr
10977 * (RelationalExpr != RelationalExpr) != RelationalExpr
10978 * which is basically what got implemented.
10979 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010980 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010981 *
10982 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010983static void
10984xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10985 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010986 CHECK_ERROR;
10987 SKIP_BLANKS;
10988 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010989 int eq;
10990 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010991
10992 if (CUR == '=') eq = 1;
10993 else eq = 0;
10994 NEXT;
10995 if (!eq) NEXT;
10996 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010997 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010998 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010999 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011000 SKIP_BLANKS;
11001 }
11002}
11003
11004/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011005 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000011006 * @ctxt: the XPath Parser context
11007 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011008 * [22] AndExpr ::= EqualityExpr
11009 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000011010 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011011 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000011012 *
11013 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011014static void
11015xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11016 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011017 CHECK_ERROR;
11018 SKIP_BLANKS;
11019 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011020 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011021 SKIP(3);
11022 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011023 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011024 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011025 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011026 SKIP_BLANKS;
11027 }
11028}
11029
11030/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000011031 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000011032 * @ctxt: the XPath Parser context
11033 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011034 * [14] Expr ::= OrExpr
11035 * [21] OrExpr ::= AndExpr
11036 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000011037 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011038 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000011039 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011040static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011041xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011042 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011043 CHECK_ERROR;
11044 SKIP_BLANKS;
11045 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011046 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011047 SKIP(2);
11048 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011049 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011050 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011051 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011052 SKIP_BLANKS;
11053 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011054 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011055 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011056 /*
11057 * This is the main place to eliminate sorting for
11058 * operations which don't require a sorted node-set.
11059 * E.g. count().
11060 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011061 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11062 }
Owen Taylor3473f882001-02-23 17:55:21 +000011063}
11064
11065/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011066 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000011067 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011068 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000011069 *
11070 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000011071 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000011072 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011073 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000011074 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011075static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011076xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011077 int op1 = ctxt->comp->last;
11078
11079 SKIP_BLANKS;
11080 if (CUR != '[') {
11081 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11082 }
11083 NEXT;
11084 SKIP_BLANKS;
11085
11086 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011087 /*
11088 * This call to xmlXPathCompileExpr() will deactivate sorting
11089 * of the predicate result.
11090 * TODO: Sorting is still activated for filters, since I'm not
11091 * sure if needed. Normally sorting should not be needed, since
11092 * a filter can only diminish the number of items in a sequence,
11093 * but won't change its order; so if the initial sequence is sorted,
11094 * subsequent sorting is not needed.
11095 */
11096 if (! filter)
11097 xmlXPathCompileExpr(ctxt, 0);
11098 else
11099 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011100 CHECK_ERROR;
11101
11102 if (CUR != ']') {
11103 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11104 }
11105
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011106 if (filter)
11107 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11108 else
11109 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011110
11111 NEXT;
11112 SKIP_BLANKS;
11113}
11114
11115/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011116 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011117 * @ctxt: the XPath Parser context
11118 * @test: pointer to a xmlXPathTestVal
11119 * @type: pointer to a xmlXPathTypeVal
11120 * @prefix: placeholder for a possible name prefix
11121 *
11122 * [7] NodeTest ::= NameTest
11123 * | NodeType '(' ')'
11124 * | 'processing-instruction' '(' Literal ')'
11125 *
11126 * [37] NameTest ::= '*'
11127 * | NCName ':' '*'
11128 * | QName
11129 * [38] NodeType ::= 'comment'
11130 * | 'text'
11131 * | 'processing-instruction'
11132 * | 'node'
11133 *
William M. Brack08171912003-12-29 02:52:11 +000011134 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011135 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011136static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011137xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11138 xmlXPathTypeVal *type, const xmlChar **prefix,
11139 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011140 int blanks;
11141
11142 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11143 STRANGE;
11144 return(NULL);
11145 }
William M. Brack78637da2003-07-31 14:47:38 +000011146 *type = (xmlXPathTypeVal) 0;
11147 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011148 *prefix = NULL;
11149 SKIP_BLANKS;
11150
11151 if ((name == NULL) && (CUR == '*')) {
11152 /*
11153 * All elements
11154 */
11155 NEXT;
11156 *test = NODE_TEST_ALL;
11157 return(NULL);
11158 }
11159
11160 if (name == NULL)
11161 name = xmlXPathParseNCName(ctxt);
11162 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011163 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011164 }
11165
William M. Brack76e95df2003-10-18 16:20:14 +000011166 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011167 SKIP_BLANKS;
11168 if (CUR == '(') {
11169 NEXT;
11170 /*
11171 * NodeType or PI search
11172 */
11173 if (xmlStrEqual(name, BAD_CAST "comment"))
11174 *type = NODE_TYPE_COMMENT;
11175 else if (xmlStrEqual(name, BAD_CAST "node"))
11176 *type = NODE_TYPE_NODE;
11177 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11178 *type = NODE_TYPE_PI;
11179 else if (xmlStrEqual(name, BAD_CAST "text"))
11180 *type = NODE_TYPE_TEXT;
11181 else {
11182 if (name != NULL)
11183 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011184 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011185 }
11186
11187 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011188
Owen Taylor3473f882001-02-23 17:55:21 +000011189 SKIP_BLANKS;
11190 if (*type == NODE_TYPE_PI) {
11191 /*
11192 * Specific case: search a PI by name.
11193 */
Owen Taylor3473f882001-02-23 17:55:21 +000011194 if (name != NULL)
11195 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011196 name = NULL;
11197 if (CUR != ')') {
11198 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011199 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011200 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011201 SKIP_BLANKS;
11202 }
Owen Taylor3473f882001-02-23 17:55:21 +000011203 }
11204 if (CUR != ')') {
11205 if (name != NULL)
11206 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011207 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011208 }
11209 NEXT;
11210 return(name);
11211 }
11212 *test = NODE_TEST_NAME;
11213 if ((!blanks) && (CUR == ':')) {
11214 NEXT;
11215
11216 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011217 * Since currently the parser context don't have a
11218 * namespace list associated:
11219 * The namespace name for this prefix can be computed
11220 * only at evaluation time. The compilation is done
11221 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011222 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011223#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011224 *prefix = xmlXPathNsLookup(ctxt->context, name);
11225 if (name != NULL)
11226 xmlFree(name);
11227 if (*prefix == NULL) {
11228 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11229 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011230#else
11231 *prefix = name;
11232#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011233
11234 if (CUR == '*') {
11235 /*
11236 * All elements
11237 */
11238 NEXT;
11239 *test = NODE_TEST_ALL;
11240 return(NULL);
11241 }
11242
11243 name = xmlXPathParseNCName(ctxt);
11244 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011245 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011246 }
11247 }
11248 return(name);
11249}
11250
11251/**
11252 * xmlXPathIsAxisName:
11253 * @name: a preparsed name token
11254 *
11255 * [6] AxisName ::= 'ancestor'
11256 * | 'ancestor-or-self'
11257 * | 'attribute'
11258 * | 'child'
11259 * | 'descendant'
11260 * | 'descendant-or-self'
11261 * | 'following'
11262 * | 'following-sibling'
11263 * | 'namespace'
11264 * | 'parent'
11265 * | 'preceding'
11266 * | 'preceding-sibling'
11267 * | 'self'
11268 *
11269 * Returns the axis or 0
11270 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011271static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011272xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011273 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011274 switch (name[0]) {
11275 case 'a':
11276 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11277 ret = AXIS_ANCESTOR;
11278 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11279 ret = AXIS_ANCESTOR_OR_SELF;
11280 if (xmlStrEqual(name, BAD_CAST "attribute"))
11281 ret = AXIS_ATTRIBUTE;
11282 break;
11283 case 'c':
11284 if (xmlStrEqual(name, BAD_CAST "child"))
11285 ret = AXIS_CHILD;
11286 break;
11287 case 'd':
11288 if (xmlStrEqual(name, BAD_CAST "descendant"))
11289 ret = AXIS_DESCENDANT;
11290 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11291 ret = AXIS_DESCENDANT_OR_SELF;
11292 break;
11293 case 'f':
11294 if (xmlStrEqual(name, BAD_CAST "following"))
11295 ret = AXIS_FOLLOWING;
11296 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11297 ret = AXIS_FOLLOWING_SIBLING;
11298 break;
11299 case 'n':
11300 if (xmlStrEqual(name, BAD_CAST "namespace"))
11301 ret = AXIS_NAMESPACE;
11302 break;
11303 case 'p':
11304 if (xmlStrEqual(name, BAD_CAST "parent"))
11305 ret = AXIS_PARENT;
11306 if (xmlStrEqual(name, BAD_CAST "preceding"))
11307 ret = AXIS_PRECEDING;
11308 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11309 ret = AXIS_PRECEDING_SIBLING;
11310 break;
11311 case 's':
11312 if (xmlStrEqual(name, BAD_CAST "self"))
11313 ret = AXIS_SELF;
11314 break;
11315 }
11316 return(ret);
11317}
11318
11319/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011320 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011321 * @ctxt: the XPath Parser context
11322 *
11323 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011324 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011325 *
11326 * [12] AbbreviatedStep ::= '.' | '..'
11327 *
11328 * [5] AxisSpecifier ::= AxisName '::'
11329 * | AbbreviatedAxisSpecifier
11330 *
11331 * [13] AbbreviatedAxisSpecifier ::= '@'?
11332 *
11333 * Modified for XPtr range support as:
11334 *
11335 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11336 * | AbbreviatedStep
11337 * | 'range-to' '(' Expr ')' Predicate*
11338 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011339 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011340 * A location step of . is short for self::node(). This is
11341 * particularly useful in conjunction with //. For example, the
11342 * location path .//para is short for
11343 * self::node()/descendant-or-self::node()/child::para
11344 * and so will select all para descendant elements of the context
11345 * node.
11346 * Similarly, a location step of .. is short for parent::node().
11347 * For example, ../title is short for parent::node()/child::title
11348 * and so will select the title children of the parent of the context
11349 * node.
11350 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011351static void
11352xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011353#ifdef LIBXML_XPTR_ENABLED
11354 int rangeto = 0;
11355 int op2 = -1;
11356#endif
11357
Owen Taylor3473f882001-02-23 17:55:21 +000011358 SKIP_BLANKS;
11359 if ((CUR == '.') && (NXT(1) == '.')) {
11360 SKIP(2);
11361 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011362 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11363 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011364 } else if (CUR == '.') {
11365 NEXT;
11366 SKIP_BLANKS;
11367 } else {
11368 xmlChar *name = NULL;
11369 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011370 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011371 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011372 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011373 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011374
11375 /*
11376 * The modification needed for XPointer change to the production
11377 */
11378#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011379 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011380 name = xmlXPathParseNCName(ctxt);
11381 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011382 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011383 xmlFree(name);
11384 SKIP_BLANKS;
11385 if (CUR != '(') {
11386 XP_ERROR(XPATH_EXPR_ERROR);
11387 }
11388 NEXT;
11389 SKIP_BLANKS;
11390
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011391 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011392 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011393 CHECK_ERROR;
11394
11395 SKIP_BLANKS;
11396 if (CUR != ')') {
11397 XP_ERROR(XPATH_EXPR_ERROR);
11398 }
11399 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011400 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011401 goto eval_predicates;
11402 }
11403 }
11404#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011405 if (CUR == '*') {
11406 axis = AXIS_CHILD;
11407 } else {
11408 if (name == NULL)
11409 name = xmlXPathParseNCName(ctxt);
11410 if (name != NULL) {
11411 axis = xmlXPathIsAxisName(name);
11412 if (axis != 0) {
11413 SKIP_BLANKS;
11414 if ((CUR == ':') && (NXT(1) == ':')) {
11415 SKIP(2);
11416 xmlFree(name);
11417 name = NULL;
11418 } else {
11419 /* an element name can conflict with an axis one :-\ */
11420 axis = AXIS_CHILD;
11421 }
Owen Taylor3473f882001-02-23 17:55:21 +000011422 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011423 axis = AXIS_CHILD;
11424 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011425 } else if (CUR == '@') {
11426 NEXT;
11427 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011428 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011429 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011430 }
Owen Taylor3473f882001-02-23 17:55:21 +000011431 }
11432
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011433 if (ctxt->error != XPATH_EXPRESSION_OK) {
11434 xmlFree(name);
11435 return;
11436 }
Owen Taylor3473f882001-02-23 17:55:21 +000011437
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011438 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011439 if (test == 0)
11440 return;
11441
Daniel Veillarded6c5492005-07-23 15:00:22 +000011442 if ((prefix != NULL) && (ctxt->context != NULL) &&
11443 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11444 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11445 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11446 }
11447 }
Owen Taylor3473f882001-02-23 17:55:21 +000011448#ifdef DEBUG_STEP
11449 xmlGenericError(xmlGenericErrorContext,
11450 "Basis : computing new set\n");
11451#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011452
Owen Taylor3473f882001-02-23 17:55:21 +000011453#ifdef DEBUG_STEP
11454 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011455 if (ctxt->value == NULL)
11456 xmlGenericError(xmlGenericErrorContext, "no value\n");
11457 else if (ctxt->value->nodesetval == NULL)
11458 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11459 else
11460 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011461#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011462
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011463#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011464eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011465#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011466 op1 = ctxt->comp->last;
11467 ctxt->comp->last = -1;
11468
Owen Taylor3473f882001-02-23 17:55:21 +000011469 SKIP_BLANKS;
11470 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011471 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011472 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011473
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011474#ifdef LIBXML_XPTR_ENABLED
11475 if (rangeto) {
11476 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11477 } else
11478#endif
11479 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11480 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011481
Owen Taylor3473f882001-02-23 17:55:21 +000011482 }
11483#ifdef DEBUG_STEP
11484 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011485 if (ctxt->value == NULL)
11486 xmlGenericError(xmlGenericErrorContext, "no value\n");
11487 else if (ctxt->value->nodesetval == NULL)
11488 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11489 else
11490 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11491 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011492#endif
11493}
11494
11495/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011496 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011497 * @ctxt: the XPath Parser context
11498 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011499 * [3] RelativeLocationPath ::= Step
11500 * | RelativeLocationPath '/' Step
11501 * | AbbreviatedRelativeLocationPath
11502 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011503 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011504 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011505 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011506static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011507xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011508(xmlXPathParserContextPtr ctxt) {
11509 SKIP_BLANKS;
11510 if ((CUR == '/') && (NXT(1) == '/')) {
11511 SKIP(2);
11512 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011513 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11514 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011515 } else if (CUR == '/') {
11516 NEXT;
11517 SKIP_BLANKS;
11518 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011519 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011520 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011521 SKIP_BLANKS;
11522 while (CUR == '/') {
11523 if ((CUR == '/') && (NXT(1) == '/')) {
11524 SKIP(2);
11525 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011526 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011527 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011528 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011529 } else if (CUR == '/') {
11530 NEXT;
11531 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011532 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011533 }
11534 SKIP_BLANKS;
11535 }
11536}
11537
11538/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011539 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011540 * @ctxt: the XPath Parser context
11541 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011542 * [1] LocationPath ::= RelativeLocationPath
11543 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011544 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011545 * | AbbreviatedAbsoluteLocationPath
11546 * [10] AbbreviatedAbsoluteLocationPath ::=
11547 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011548 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011549 * Compile a location path
11550 *
Owen Taylor3473f882001-02-23 17:55:21 +000011551 * // is short for /descendant-or-self::node()/. For example,
11552 * //para is short for /descendant-or-self::node()/child::para and
11553 * so will select any para element in the document (even a para element
11554 * that is a document element will be selected by //para since the
11555 * document element node is a child of the root node); div//para is
11556 * short for div/descendant-or-self::node()/child::para and so will
11557 * select all para descendants of div children.
11558 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011559static void
11560xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011561 SKIP_BLANKS;
11562 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011563 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011564 } else {
11565 while (CUR == '/') {
11566 if ((CUR == '/') && (NXT(1) == '/')) {
11567 SKIP(2);
11568 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011569 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11570 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011571 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011572 } else if (CUR == '/') {
11573 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011574 SKIP_BLANKS;
11575 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011576 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011577 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011578 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011579 }
Martin729601f2009-10-12 22:42:26 +020011580 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011581 }
11582 }
11583}
11584
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011585/************************************************************************
11586 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011587 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011588 * *
11589 ************************************************************************/
11590
Daniel Veillardf06307e2001-07-03 10:35:50 +000011591static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011592xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11593
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011594#ifdef DEBUG_STEP
11595static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011596xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011597 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011598{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011599 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011600 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011601 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011602 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011603 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011604 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011605 xmlGenericError(xmlGenericErrorContext,
11606 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011607 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011608 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011609 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011610 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011611 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011612 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011613 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011614 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011615 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011616 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011617 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011618 xmlGenericError(xmlGenericErrorContext,
11619 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011620 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011621 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011622 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011623 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011624 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011625 xmlGenericError(xmlGenericErrorContext,
11626 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011627 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011628 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011629 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011630 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011631 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011632 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011633 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011634 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011635 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011636 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011637 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011638 xmlGenericError(xmlGenericErrorContext,
11639 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011640 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011641 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011642 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011643 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011644 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011645 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011646 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011647 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011648 case NODE_TEST_NONE:
11649 xmlGenericError(xmlGenericErrorContext,
11650 " searching for none !!!\n");
11651 break;
11652 case NODE_TEST_TYPE:
11653 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011654 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011655 break;
11656 case NODE_TEST_PI:
11657 xmlGenericError(xmlGenericErrorContext,
11658 " searching for PI !!!\n");
11659 break;
11660 case NODE_TEST_ALL:
11661 xmlGenericError(xmlGenericErrorContext,
11662 " searching for *\n");
11663 break;
11664 case NODE_TEST_NS:
11665 xmlGenericError(xmlGenericErrorContext,
11666 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011667 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011668 break;
11669 case NODE_TEST_NAME:
11670 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011671 " searching for name %s\n", op->value5);
11672 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011673 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011674 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011675 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011676 }
11677 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011678}
11679#endif /* DEBUG_STEP */
11680
11681static int
11682xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11683 xmlXPathStepOpPtr op,
11684 xmlNodeSetPtr set,
11685 int contextSize,
11686 int hasNsNodes)
11687{
11688 if (op->ch1 != -1) {
11689 xmlXPathCompExprPtr comp = ctxt->comp;
11690 /*
11691 * Process inner predicates first.
11692 */
11693 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11694 /*
11695 * TODO: raise an internal error.
11696 */
11697 }
11698 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11699 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11700 CHECK_ERROR0;
11701 if (contextSize <= 0)
11702 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011703 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011704 if (op->ch2 != -1) {
11705 xmlXPathContextPtr xpctxt = ctxt->context;
11706 xmlNodePtr contextNode, oldContextNode;
11707 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011708 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011709 xmlXPathStepOpPtr exprOp;
11710 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11711
11712#ifdef LIBXML_XPTR_ENABLED
11713 /*
11714 * URGENT TODO: Check the following:
11715 * We don't expect location sets if evaluating prediates, right?
11716 * Only filters should expect location sets, right?
11717 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011718#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011719 /*
11720 * SPEC XPath 1.0:
11721 * "For each node in the node-set to be filtered, the
11722 * PredicateExpr is evaluated with that node as the
11723 * context node, with the number of nodes in the
11724 * node-set as the context size, and with the proximity
11725 * position of the node in the node-set with respect to
11726 * the axis as the context position;"
11727 * @oldset is the node-set" to be filtered.
11728 *
11729 * SPEC XPath 1.0:
11730 * "only predicates change the context position and
11731 * context size (see [2.4 Predicates])."
11732 * Example:
11733 * node-set context pos
11734 * nA 1
11735 * nB 2
11736 * nC 3
11737 * After applying predicate [position() > 1] :
11738 * node-set context pos
11739 * nB 1
11740 * nC 2
11741 */
11742 oldContextNode = xpctxt->node;
11743 oldContextDoc = xpctxt->doc;
11744 /*
11745 * Get the expression of this predicate.
11746 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011747 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011748 newContextSize = 0;
11749 for (i = 0; i < set->nodeNr; i++) {
11750 if (set->nodeTab[i] == NULL)
11751 continue;
11752
11753 contextNode = set->nodeTab[i];
11754 xpctxt->node = contextNode;
11755 xpctxt->contextSize = contextSize;
11756 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011757
11758 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011759 * Also set the xpath document in case things like
11760 * key() are evaluated in the predicate.
11761 */
11762 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11763 (contextNode->doc != NULL))
11764 xpctxt->doc = contextNode->doc;
11765 /*
11766 * Evaluate the predicate expression with 1 context node
11767 * at a time; this node is packaged into a node set; this
11768 * node set is handed over to the evaluation mechanism.
11769 */
11770 if (contextObj == NULL)
11771 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011772 else {
11773 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11774 contextNode) < 0) {
11775 ctxt->error = XPATH_MEMORY_ERROR;
11776 goto evaluation_exit;
11777 }
11778 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011779
11780 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011781
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011782 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011783
William M. Brack0bcec062007-02-14 02:15:19 +000011784 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11785 xmlXPathNodeSetClear(set, hasNsNodes);
11786 newContextSize = 0;
11787 goto evaluation_exit;
11788 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011789
11790 if (res != 0) {
11791 newContextSize++;
11792 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011793 /*
11794 * Remove the entry from the initial node set.
11795 */
11796 set->nodeTab[i] = NULL;
11797 if (contextNode->type == XML_NAMESPACE_DECL)
11798 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011799 }
11800 if (ctxt->value == contextObj) {
11801 /*
11802 * Don't free the temporary XPath object holding the
11803 * context node, in order to avoid massive recreation
11804 * inside this loop.
11805 */
11806 valuePop(ctxt);
11807 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11808 } else {
11809 /*
11810 * TODO: The object was lost in the evaluation machinery.
11811 * Can this happen? Maybe in internal-error cases.
11812 */
11813 contextObj = NULL;
11814 }
11815 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011816
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011817 if (contextObj != NULL) {
11818 if (ctxt->value == contextObj)
11819 valuePop(ctxt);
11820 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011821 }
William M. Brack0bcec062007-02-14 02:15:19 +000011822evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011823 if (exprRes != NULL)
11824 xmlXPathReleaseObject(ctxt->context, exprRes);
11825 /*
11826 * Reset/invalidate the context.
11827 */
11828 xpctxt->node = oldContextNode;
11829 xpctxt->doc = oldContextDoc;
11830 xpctxt->contextSize = -1;
11831 xpctxt->proximityPosition = -1;
11832 return(newContextSize);
11833 }
11834 return(contextSize);
11835}
11836
11837static int
11838xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11839 xmlXPathStepOpPtr op,
11840 xmlNodeSetPtr set,
11841 int contextSize,
11842 int minPos,
11843 int maxPos,
11844 int hasNsNodes)
11845{
11846 if (op->ch1 != -1) {
11847 xmlXPathCompExprPtr comp = ctxt->comp;
11848 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11849 /*
11850 * TODO: raise an internal error.
11851 */
11852 }
11853 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11854 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11855 CHECK_ERROR0;
11856 if (contextSize <= 0)
11857 return(0);
11858 }
11859 /*
11860 * Check if the node set contains a sufficient number of nodes for
11861 * the requested range.
11862 */
11863 if (contextSize < minPos) {
11864 xmlXPathNodeSetClear(set, hasNsNodes);
11865 return(0);
11866 }
11867 if (op->ch2 == -1) {
11868 /*
11869 * TODO: Can this ever happen?
11870 */
11871 return (contextSize);
11872 } else {
11873 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011874 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011875 xmlXPathStepOpPtr exprOp;
11876 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11877 xmlNodePtr oldContextNode, contextNode = NULL;
11878 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011879 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011880
11881#ifdef LIBXML_XPTR_ENABLED
11882 /*
11883 * URGENT TODO: Check the following:
11884 * We don't expect location sets if evaluating prediates, right?
11885 * Only filters should expect location sets, right?
11886 */
11887#endif /* LIBXML_XPTR_ENABLED */
11888
11889 /*
11890 * Save old context.
11891 */
11892 oldContextNode = xpctxt->node;
11893 oldContextDoc = xpctxt->doc;
11894 /*
11895 * Get the expression of this predicate.
11896 */
11897 exprOp = &ctxt->comp->steps[op->ch2];
11898 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011899 xmlXPathObjectPtr tmp;
11900
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011901 if (set->nodeTab[i] == NULL)
11902 continue;
11903
11904 contextNode = set->nodeTab[i];
11905 xpctxt->node = contextNode;
11906 xpctxt->contextSize = contextSize;
11907 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011908
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011909 /*
11910 * Initialize the new set.
11911 * Also set the xpath document in case things like
11912 * key() evaluation are attempted on the predicate
11913 */
11914 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11915 (contextNode->doc != NULL))
11916 xpctxt->doc = contextNode->doc;
11917 /*
11918 * Evaluate the predicate expression with 1 context node
11919 * at a time; this node is packaged into a node set; this
11920 * node set is handed over to the evaluation mechanism.
11921 */
11922 if (contextObj == NULL)
11923 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011924 else {
11925 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11926 contextNode) < 0) {
11927 ctxt->error = XPATH_MEMORY_ERROR;
11928 goto evaluation_exit;
11929 }
11930 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011931
11932 valuePush(ctxt, contextObj);
Nick Wellnhofer0f3b8432017-06-01 23:12:19 +020011933 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011934 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011935 xmlXPathPopFrame(ctxt, frame);
Nick Wellnhofer0f3b8432017-06-01 23:12:19 +020011936 tmp = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011937
William M. Brackf1794562007-08-23 12:58:13 +000011938 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011939 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011940 /*
11941 * Free up the result
11942 * then pop off contextObj, which will be freed later
11943 */
11944 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011945 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011946 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011947 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011948 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011949 /* push the result back onto the stack */
11950 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011951
11952 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011953 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011954
11955 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011956 /*
11957 * Fits in the requested range.
11958 */
11959 newContextSize++;
11960 if (minPos == maxPos) {
11961 /*
11962 * Only 1 node was requested.
11963 */
11964 if (contextNode->type == XML_NAMESPACE_DECL) {
11965 /*
11966 * As always: take care of those nasty
11967 * namespace nodes.
11968 */
11969 set->nodeTab[i] = NULL;
11970 }
11971 xmlXPathNodeSetClear(set, hasNsNodes);
11972 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011973 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011974 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011975 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011976 if (pos == maxPos) {
11977 /*
11978 * We are done.
11979 */
11980 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11981 goto evaluation_exit;
11982 }
11983 } else {
11984 /*
11985 * Remove the entry from the initial node set.
11986 */
11987 set->nodeTab[i] = NULL;
11988 if (contextNode->type == XML_NAMESPACE_DECL)
11989 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11990 }
11991 if (exprRes != NULL) {
11992 xmlXPathReleaseObject(ctxt->context, exprRes);
11993 exprRes = NULL;
11994 }
11995 if (ctxt->value == contextObj) {
11996 /*
11997 * Don't free the temporary XPath object holding the
11998 * context node, in order to avoid massive recreation
11999 * inside this loop.
12000 */
12001 valuePop(ctxt);
12002 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
12003 } else {
12004 /*
12005 * The object was lost in the evaluation machinery.
12006 * Can this happen? Maybe in case of internal-errors.
12007 */
12008 contextObj = NULL;
12009 }
12010 }
12011 goto evaluation_exit;
12012
12013evaluation_error:
12014 xmlXPathNodeSetClear(set, hasNsNodes);
12015 newContextSize = 0;
12016
12017evaluation_exit:
12018 if (contextObj != NULL) {
12019 if (ctxt->value == contextObj)
12020 valuePop(ctxt);
12021 xmlXPathReleaseObject(xpctxt, contextObj);
12022 }
12023 if (exprRes != NULL)
12024 xmlXPathReleaseObject(ctxt->context, exprRes);
12025 /*
12026 * Reset/invalidate the context.
12027 */
12028 xpctxt->node = oldContextNode;
12029 xpctxt->doc = oldContextDoc;
12030 xpctxt->contextSize = -1;
12031 xpctxt->proximityPosition = -1;
12032 return(newContextSize);
12033 }
12034 return(contextSize);
12035}
12036
12037static int
12038xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000012039 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012040 int *maxPos)
12041{
12042
12043 xmlXPathStepOpPtr exprOp;
12044
12045 /*
12046 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12047 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012048
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012049 /*
12050 * If not -1, then ch1 will point to:
12051 * 1) For predicates (XPATH_OP_PREDICATE):
12052 * - an inner predicate operator
12053 * 2) For filters (XPATH_OP_FILTER):
12054 * - an inner filter operater OR
12055 * - an expression selecting the node set.
12056 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012057 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012058 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12059 return(0);
12060
12061 if (op->ch2 != -1) {
12062 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012063 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012064 return(0);
12065
12066 if ((exprOp != NULL) &&
12067 (exprOp->op == XPATH_OP_VALUE) &&
12068 (exprOp->value4 != NULL) &&
12069 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12070 {
Nick Wellnhofera58331a2017-05-29 21:02:21 +020012071 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12072
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012073 /*
12074 * We have a "[n]" predicate here.
12075 * TODO: Unfortunately this simplistic test here is not
12076 * able to detect a position() predicate in compound
12077 * expressions like "[@attr = 'a" and position() = 1],
12078 * and even not the usage of position() in
12079 * "[position() = 1]"; thus - obviously - a position-range,
12080 * like it "[position() < 5]", is also not detected.
12081 * Maybe we could rewrite the AST to ease the optimization.
12082 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012083
Nick Wellnhofera58331a2017-05-29 21:02:21 +020012084 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12085 *maxPos = (int) floatval;
12086 if (floatval == (double) *maxPos)
12087 return(1);
12088 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012089 }
12090 return(0);
12091}
12092
12093static int
12094xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12095 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012096 xmlNodePtr * first, xmlNodePtr * last,
12097 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012098{
12099
12100#define XP_TEST_HIT \
12101 if (hasAxisRange != 0) { \
12102 if (++pos == maxPos) { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012103 if (addNode(seq, cur) < 0) \
12104 ctxt->error = XPATH_MEMORY_ERROR; \
12105 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012106 } else { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012107 if (addNode(seq, cur) < 0) \
12108 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012109 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012110
12111#define XP_TEST_HIT_NS \
12112 if (hasAxisRange != 0) { \
12113 if (++pos == maxPos) { \
12114 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012115 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12116 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012117 goto axis_range_end; } \
12118 } else { \
12119 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012120 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12121 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012122 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012123
12124 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12125 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12126 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12127 const xmlChar *prefix = op->value4;
12128 const xmlChar *name = op->value5;
12129 const xmlChar *URI = NULL;
12130
12131#ifdef DEBUG_STEP
12132 int nbMatches = 0, prevMatches = 0;
12133#endif
12134 int total = 0, hasNsNodes = 0;
12135 /* The popped object holding the context nodes */
12136 xmlXPathObjectPtr obj;
12137 /* The set of context nodes for the node tests */
12138 xmlNodeSetPtr contextSeq;
12139 int contextIdx;
12140 xmlNodePtr contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012141 /* The final resulting node set wrt to all context nodes */
12142 xmlNodeSetPtr outSeq;
12143 /*
12144 * The temporary resulting node set wrt 1 context node.
12145 * Used to feed predicate evaluation.
12146 */
12147 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012148 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012149 /* First predicate operator */
12150 xmlXPathStepOpPtr predOp;
12151 int maxPos; /* The requested position() (when a "[n]" predicate) */
12152 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012153 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012154
12155 xmlXPathTraversalFunction next = NULL;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012156 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012157 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012158 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012159 xmlXPathContextPtr xpctxt = ctxt->context;
12160
12161
12162 CHECK_TYPE0(XPATH_NODESET);
12163 obj = valuePop(ctxt);
12164 /*
12165 * Setup namespaces.
12166 */
12167 if (prefix != NULL) {
12168 URI = xmlXPathNsLookup(xpctxt, prefix);
12169 if (URI == NULL) {
12170 xmlXPathReleaseObject(xpctxt, obj);
12171 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12172 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012173 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012174 /*
12175 * Setup axis.
12176 *
12177 * MAYBE FUTURE TODO: merging optimizations:
12178 * - If the nodes to be traversed wrt to the initial nodes and
12179 * the current axis cannot overlap, then we could avoid searching
12180 * for duplicates during the merge.
12181 * But the question is how/when to evaluate if they cannot overlap.
12182 * Example: if we know that for two initial nodes, the one is
12183 * not in the ancestor-or-self axis of the other, then we could safely
12184 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12185 * the descendant-or-self axis.
12186 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012187 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12188 switch (axis) {
12189 case AXIS_ANCESTOR:
12190 first = NULL;
12191 next = xmlXPathNextAncestor;
12192 break;
12193 case AXIS_ANCESTOR_OR_SELF:
12194 first = NULL;
12195 next = xmlXPathNextAncestorOrSelf;
12196 break;
12197 case AXIS_ATTRIBUTE:
12198 first = NULL;
12199 last = NULL;
12200 next = xmlXPathNextAttribute;
12201 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12202 break;
12203 case AXIS_CHILD:
12204 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012205 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12206 (type == NODE_TYPE_NODE))
12207 {
12208 /*
12209 * Optimization if an element node type is 'element'.
12210 */
12211 next = xmlXPathNextChildElement;
12212 } else
12213 next = xmlXPathNextChild;
12214 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12215 break;
12216 case AXIS_DESCENDANT:
12217 last = NULL;
12218 next = xmlXPathNextDescendant;
12219 break;
12220 case AXIS_DESCENDANT_OR_SELF:
12221 last = NULL;
12222 next = xmlXPathNextDescendantOrSelf;
12223 break;
12224 case AXIS_FOLLOWING:
12225 last = NULL;
12226 next = xmlXPathNextFollowing;
12227 break;
12228 case AXIS_FOLLOWING_SIBLING:
12229 last = NULL;
12230 next = xmlXPathNextFollowingSibling;
12231 break;
12232 case AXIS_NAMESPACE:
12233 first = NULL;
12234 last = NULL;
12235 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12236 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12237 break;
12238 case AXIS_PARENT:
12239 first = NULL;
12240 next = xmlXPathNextParent;
12241 break;
12242 case AXIS_PRECEDING:
12243 first = NULL;
12244 next = xmlXPathNextPrecedingInternal;
12245 break;
12246 case AXIS_PRECEDING_SIBLING:
12247 first = NULL;
12248 next = xmlXPathNextPrecedingSibling;
12249 break;
12250 case AXIS_SELF:
12251 first = NULL;
12252 last = NULL;
12253 next = xmlXPathNextSelf;
12254 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12255 break;
12256 }
12257
12258#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012259 xmlXPathDebugDumpStepAxis(op,
12260 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012261#endif
12262
12263 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012264 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012265 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012266 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012267 contextSeq = obj->nodesetval;
12268 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12269 xmlXPathReleaseObject(xpctxt, obj);
12270 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12271 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012272 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012273 /*
12274 * Predicate optimization ---------------------------------------------
12275 * If this step has a last predicate, which contains a position(),
12276 * then we'll optimize (although not exactly "position()", but only
12277 * the short-hand form, i.e., "[n]".
12278 *
12279 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012280 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012281 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12282 * ROOT -- op->ch1
12283 * PREDICATE -- op->ch2 (predOp)
12284 * PREDICATE -- predOp->ch1 = [parent::bar]
12285 * SORT
12286 * COLLECT 'parent' 'name' 'node' bar
12287 * NODE
12288 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12289 *
12290 */
12291 maxPos = 0;
12292 predOp = NULL;
12293 hasPredicateRange = 0;
12294 hasAxisRange = 0;
12295 if (op->ch2 != -1) {
12296 /*
12297 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12298 */
12299 predOp = &ctxt->comp->steps[op->ch2];
12300 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12301 if (predOp->ch1 != -1) {
12302 /*
12303 * Use the next inner predicate operator.
12304 */
12305 predOp = &ctxt->comp->steps[predOp->ch1];
12306 hasPredicateRange = 1;
12307 } else {
12308 /*
12309 * There's no other predicate than the [n] predicate.
12310 */
12311 predOp = NULL;
12312 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012313 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012314 }
12315 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012316 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012317 /*
12318 * Axis traversal -----------------------------------------------------
12319 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012320 /*
12321 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012322 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012323 * - For the namespace axis, the principal node type is namespace.
12324 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012325 *
12326 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012327 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012328 * select all element children of the context node
12329 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012330 oldContextNode = xpctxt->node;
12331 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012332 outSeq = NULL;
12333 seq = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012334 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012335 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012336
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012337
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012338 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12339 (ctxt->error == XPATH_EXPRESSION_OK)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012340 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012341
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012342 if (seq == NULL) {
12343 seq = xmlXPathNodeSetCreate(NULL);
12344 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012345 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012346 goto error;
12347 }
12348 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012349 /*
12350 * Traverse the axis and test the nodes.
12351 */
12352 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012353 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012354 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012355 do {
12356 cur = next(ctxt, cur);
12357 if (cur == NULL)
12358 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012359
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012360 /*
12361 * QUESTION TODO: What does the "first" and "last" stuff do?
12362 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012363 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012364 if (*first == cur)
12365 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012366 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012367#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012368 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012369#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012370 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012371#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012372 {
12373 break;
12374 }
12375 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012376 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012377 if (*last == cur)
12378 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012379 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012380#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012381 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012382#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012383 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012384#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012385 {
12386 break;
12387 }
12388 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012389
12390 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012391
Daniel Veillardf06307e2001-07-03 10:35:50 +000012392#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012393 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12394#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012395
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012396 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012397 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012398 total = 0;
12399 STRANGE
12400 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012401 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012402 if (type == NODE_TYPE_NODE) {
12403 switch (cur->type) {
12404 case XML_DOCUMENT_NODE:
12405 case XML_HTML_DOCUMENT_NODE:
12406#ifdef LIBXML_DOCB_ENABLED
12407 case XML_DOCB_DOCUMENT_NODE:
12408#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012409 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012410 case XML_ATTRIBUTE_NODE:
12411 case XML_PI_NODE:
12412 case XML_COMMENT_NODE:
12413 case XML_CDATA_SECTION_NODE:
12414 case XML_TEXT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012415 XP_TEST_HIT
12416 break;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012417 case XML_NAMESPACE_DECL: {
12418 if (axis == AXIS_NAMESPACE) {
12419 XP_TEST_HIT_NS
12420 } else {
Nick Wellnhofer6eb08942016-05-05 16:49:00 +020012421 hasNsNodes = 1;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012422 XP_TEST_HIT
12423 }
12424 break;
12425 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012426 default:
12427 break;
12428 }
12429 } else if (cur->type == type) {
Daniel Veillard713434d2012-09-26 10:21:06 +080012430 if (cur->type == XML_NAMESPACE_DECL)
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012431 XP_TEST_HIT_NS
12432 else
12433 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012434 } else if ((type == NODE_TYPE_TEXT) &&
12435 (cur->type == XML_CDATA_SECTION_NODE))
12436 {
12437 XP_TEST_HIT
12438 }
12439 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012440 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012441 if ((cur->type == XML_PI_NODE) &&
12442 ((name == NULL) || xmlStrEqual(name, cur->name)))
12443 {
12444 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012445 }
12446 break;
12447 case NODE_TEST_ALL:
12448 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012449 if (cur->type == XML_ATTRIBUTE_NODE)
12450 {
Nick Wellnhofere8de99f2013-08-05 01:26:25 +020012451 if (prefix == NULL)
12452 {
12453 XP_TEST_HIT
12454 } else if ((cur->ns != NULL) &&
12455 (xmlStrEqual(URI, cur->ns->href)))
12456 {
12457 XP_TEST_HIT
12458 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012459 }
12460 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012461 if (cur->type == XML_NAMESPACE_DECL)
12462 {
12463 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012464 }
12465 } else {
12466 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012467 if (prefix == NULL)
12468 {
12469 XP_TEST_HIT
12470
Daniel Veillardf06307e2001-07-03 10:35:50 +000012471 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012472 (xmlStrEqual(URI, cur->ns->href)))
12473 {
12474 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012475 }
12476 }
12477 }
12478 break;
12479 case NODE_TEST_NS:{
12480 TODO;
12481 break;
12482 }
12483 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012484 if (axis == AXIS_ATTRIBUTE) {
12485 if (cur->type != XML_ATTRIBUTE_NODE)
12486 break;
12487 } else if (axis == AXIS_NAMESPACE) {
12488 if (cur->type != XML_NAMESPACE_DECL)
12489 break;
12490 } else {
12491 if (cur->type != XML_ELEMENT_NODE)
12492 break;
12493 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012494 switch (cur->type) {
12495 case XML_ELEMENT_NODE:
12496 if (xmlStrEqual(name, cur->name)) {
12497 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012498 if (cur->ns == NULL)
12499 {
12500 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012501 }
12502 } else {
12503 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012504 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012505 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012506 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012507 }
12508 }
12509 }
12510 break;
12511 case XML_ATTRIBUTE_NODE:{
12512 xmlAttrPtr attr = (xmlAttrPtr) cur;
12513
12514 if (xmlStrEqual(name, attr->name)) {
12515 if (prefix == NULL) {
12516 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012517 (attr->ns->prefix == NULL))
12518 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012519 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012520 }
12521 } else {
12522 if ((attr->ns != NULL) &&
12523 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012524 attr->ns->href)))
12525 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012526 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012527 }
12528 }
12529 }
12530 break;
12531 }
12532 case XML_NAMESPACE_DECL:
12533 if (cur->type == XML_NAMESPACE_DECL) {
12534 xmlNsPtr ns = (xmlNsPtr) cur;
12535
12536 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012537 && (xmlStrEqual(ns->prefix, name)))
12538 {
12539 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012540 }
12541 }
12542 break;
12543 default:
12544 break;
12545 }
12546 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012547 } /* switch(test) */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012548 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012549
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012550 goto apply_predicates;
12551
Daniel Veillard45490ae2008-07-29 09:13:19 +000012552axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012553 /*
12554 * We have a "/foo[n]", and position() = n was reached.
12555 * Note that we can have as well "/foo/::parent::foo[1]", so
12556 * a duplicate-aware merge is still needed.
12557 * Merge with the result.
12558 */
12559 if (outSeq == NULL) {
12560 outSeq = seq;
12561 seq = NULL;
12562 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012563 outSeq = mergeAndClear(outSeq, seq, 0);
12564 /*
12565 * Break if only a true/false result was requested.
12566 */
12567 if (toBool)
12568 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012569 continue;
12570
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012571first_hit: /* ---------------------------------------------------------- */
12572 /*
12573 * Break if only a true/false result was requested and
12574 * no predicates existed and a node test succeeded.
12575 */
12576 if (outSeq == NULL) {
12577 outSeq = seq;
12578 seq = NULL;
12579 } else
12580 outSeq = mergeAndClear(outSeq, seq, 0);
12581 break;
12582
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012583#ifdef DEBUG_STEP
12584 if (seq != NULL)
12585 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012586#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012587
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012588apply_predicates: /* --------------------------------------------------- */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012589 if (ctxt->error != XPATH_EXPRESSION_OK)
12590 goto error;
12591
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012592 /*
12593 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012594 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012595 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12596 /*
12597 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012598 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012599 /*
12600 * QUESTION TODO: The old predicate evaluation took into
12601 * account location-sets.
12602 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12603 * Do we expect such a set here?
12604 * All what I learned now from the evaluation semantics
12605 * does not indicate that a location-set will be processed
12606 * here, so this looks OK.
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012607 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012608 /*
12609 * Iterate over all predicates, starting with the outermost
12610 * predicate.
12611 * TODO: Problem: we cannot execute the inner predicates first
12612 * since we cannot go back *up* the operator tree!
12613 * Options we have:
12614 * 1) Use of recursive functions (like is it currently done
12615 * via xmlXPathCompOpEval())
12616 * 2) Add a predicate evaluation information stack to the
12617 * context struct
12618 * 3) Change the way the operators are linked; we need a
12619 * "parent" field on xmlXPathStepOp
12620 *
12621 * For the moment, I'll try to solve this with a recursive
12622 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012623 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012624 size = seq->nodeNr;
12625 if (hasPredicateRange != 0)
12626 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12627 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12628 else
12629 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12630 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012631
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012632 if (ctxt->error != XPATH_EXPRESSION_OK) {
12633 total = 0;
12634 goto error;
12635 }
12636 /*
12637 * Add the filtered set of nodes to the result node set.
12638 */
12639 if (newSize == 0) {
12640 /*
12641 * The predicates filtered all nodes out.
12642 */
12643 xmlXPathNodeSetClear(seq, hasNsNodes);
12644 } else if (seq->nodeNr > 0) {
12645 /*
12646 * Add to result set.
12647 */
12648 if (outSeq == NULL) {
12649 if (size != newSize) {
12650 /*
12651 * We need to merge and clear here, since
12652 * the sequence will contained NULLed entries.
12653 */
12654 outSeq = mergeAndClear(NULL, seq, 1);
12655 } else {
12656 outSeq = seq;
12657 seq = NULL;
12658 }
12659 } else
12660 outSeq = mergeAndClear(outSeq, seq,
12661 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012662 /*
12663 * Break if only a true/false result was requested.
12664 */
12665 if (toBool)
12666 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012667 }
12668 } else if (seq->nodeNr > 0) {
12669 /*
12670 * Add to result set.
12671 */
12672 if (outSeq == NULL) {
12673 outSeq = seq;
12674 seq = NULL;
12675 } else {
12676 outSeq = mergeAndClear(outSeq, seq, 0);
12677 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012678 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012679 }
12680
12681error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012682 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012683 /*
12684 * QUESTION TODO: What does this do and why?
12685 * TODO: Do we have to do this also for the "error"
12686 * cleanup further down?
12687 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012688 ctxt->value->boolval = 1;
12689 ctxt->value->user = obj->user;
12690 obj->user = NULL;
12691 obj->boolval = 0;
12692 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012693 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012694
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012695 /*
12696 * Ensure we return at least an emtpy set.
12697 */
12698 if (outSeq == NULL) {
12699 if ((seq != NULL) && (seq->nodeNr == 0))
12700 outSeq = seq;
12701 else
12702 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012703 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012704 }
12705 if ((seq != NULL) && (seq != outSeq)) {
12706 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012707 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012708 /*
12709 * Hand over the result. Better to push the set also in
12710 * case of errors.
12711 */
12712 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12713 /*
12714 * Reset the context node.
12715 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012716 xpctxt->node = oldContextNode;
Nick Wellnhofer82b73032016-04-30 17:53:10 +020012717 /*
12718 * When traversing the namespace axis in "toBool" mode, it's
12719 * possible that tmpNsList wasn't freed.
12720 */
12721 if (xpctxt->tmpNsList != NULL) {
12722 xmlFree(xpctxt->tmpNsList);
12723 xpctxt->tmpNsList = NULL;
12724 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012725
12726#ifdef DEBUG_STEP
12727 xmlGenericError(xmlGenericErrorContext,
12728 "\nExamined %d nodes, found %d nodes at that step\n",
12729 total, nbMatches);
12730#endif
12731
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012732 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012733}
12734
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012735static int
12736xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12737 xmlXPathStepOpPtr op, xmlNodePtr * first);
12738
Daniel Veillardf06307e2001-07-03 10:35:50 +000012739/**
12740 * xmlXPathCompOpEvalFirst:
12741 * @ctxt: the XPath parser context with the compiled expression
12742 * @op: an XPath compiled operation
12743 * @first: the first elem found so far
12744 *
12745 * Evaluate the Precompiled XPath operation searching only the first
12746 * element in document order
12747 *
12748 * Returns the number of examined objects.
12749 */
12750static int
12751xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12752 xmlXPathStepOpPtr op, xmlNodePtr * first)
12753{
12754 int total = 0, cur;
12755 xmlXPathCompExprPtr comp;
12756 xmlXPathObjectPtr arg1, arg2;
12757
Daniel Veillard556c6682001-10-06 09:59:51 +000012758 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012759 comp = ctxt->comp;
12760 switch (op->op) {
12761 case XPATH_OP_END:
12762 return (0);
12763 case XPATH_OP_UNION:
12764 total =
12765 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12766 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012767 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012768 if ((ctxt->value != NULL)
12769 && (ctxt->value->type == XPATH_NODESET)
12770 && (ctxt->value->nodesetval != NULL)
12771 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12772 /*
12773 * limit tree traversing to first node in the result
12774 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012775 /*
12776 * OPTIMIZE TODO: This implicitely sorts
12777 * the result, even if not needed. E.g. if the argument
12778 * of the count() function, no sorting is needed.
12779 * OPTIMIZE TODO: How do we know if the node-list wasn't
12780 * aready sorted?
12781 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012782 if (ctxt->value->nodesetval->nodeNr > 1)
12783 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012784 *first = ctxt->value->nodesetval->nodeTab[0];
12785 }
12786 cur =
12787 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12788 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012789 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012790
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012791 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012792 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012793 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12794 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12795 xmlXPathReleaseObject(ctxt->context, arg1);
12796 xmlXPathReleaseObject(ctxt->context, arg2);
12797 XP_ERROR0(XPATH_INVALID_TYPE);
12798 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012799
12800 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12801 arg2->nodesetval);
12802 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012803 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012804 /* optimizer */
12805 if (total > cur)
12806 xmlXPathCompSwap(op);
12807 return (total + cur);
12808 case XPATH_OP_ROOT:
12809 xmlXPathRoot(ctxt);
12810 return (0);
12811 case XPATH_OP_NODE:
12812 if (op->ch1 != -1)
12813 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012814 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012815 if (op->ch2 != -1)
12816 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012817 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012818 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12819 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012820 return (total);
12821 case XPATH_OP_RESET:
12822 if (op->ch1 != -1)
12823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012824 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012825 if (op->ch2 != -1)
12826 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012827 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012828 ctxt->context->node = NULL;
12829 return (total);
12830 case XPATH_OP_COLLECT:{
12831 if (op->ch1 == -1)
12832 return (total);
12833
12834 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012835 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012836
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012837 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012838 return (total);
12839 }
12840 case XPATH_OP_VALUE:
12841 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012842 xmlXPathCacheObjectCopy(ctxt->context,
12843 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012844 return (0);
12845 case XPATH_OP_SORT:
12846 if (op->ch1 != -1)
12847 total +=
12848 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12849 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012850 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012851 if ((ctxt->value != NULL)
12852 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012853 && (ctxt->value->nodesetval != NULL)
12854 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012855 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12856 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012857#ifdef XP_OPTIMIZED_FILTER_FIRST
12858 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012859 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012860 return (total);
12861#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012862 default:
12863 return (xmlXPathCompOpEval(ctxt, op));
12864 }
12865}
12866
12867/**
12868 * xmlXPathCompOpEvalLast:
12869 * @ctxt: the XPath parser context with the compiled expression
12870 * @op: an XPath compiled operation
12871 * @last: the last elem found so far
12872 *
12873 * Evaluate the Precompiled XPath operation searching only the last
12874 * element in document order
12875 *
William M. Brack08171912003-12-29 02:52:11 +000012876 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012877 */
12878static int
12879xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12880 xmlNodePtr * last)
12881{
12882 int total = 0, cur;
12883 xmlXPathCompExprPtr comp;
12884 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012885 xmlNodePtr bak;
12886 xmlDocPtr bakd;
12887 int pp;
12888 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012889
Daniel Veillard556c6682001-10-06 09:59:51 +000012890 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012891 comp = ctxt->comp;
12892 switch (op->op) {
12893 case XPATH_OP_END:
12894 return (0);
12895 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012896 bakd = ctxt->context->doc;
12897 bak = ctxt->context->node;
12898 pp = ctxt->context->proximityPosition;
12899 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012900 total =
12901 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012902 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012903 if ((ctxt->value != NULL)
12904 && (ctxt->value->type == XPATH_NODESET)
12905 && (ctxt->value->nodesetval != NULL)
12906 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12907 /*
12908 * limit tree traversing to first node in the result
12909 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012910 if (ctxt->value->nodesetval->nodeNr > 1)
12911 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012912 *last =
12913 ctxt->value->nodesetval->nodeTab[ctxt->value->
12914 nodesetval->nodeNr -
12915 1];
12916 }
William M. Brackce4fc562004-01-22 02:47:18 +000012917 ctxt->context->doc = bakd;
12918 ctxt->context->node = bak;
12919 ctxt->context->proximityPosition = pp;
12920 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012921 cur =
12922 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012923 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012924 if ((ctxt->value != NULL)
12925 && (ctxt->value->type == XPATH_NODESET)
12926 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012927 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012928 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012929
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012930 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012931 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012932 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12933 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12934 xmlXPathReleaseObject(ctxt->context, arg1);
12935 xmlXPathReleaseObject(ctxt->context, arg2);
12936 XP_ERROR0(XPATH_INVALID_TYPE);
12937 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012938
12939 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12940 arg2->nodesetval);
12941 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012942 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012943 /* optimizer */
12944 if (total > cur)
12945 xmlXPathCompSwap(op);
12946 return (total + cur);
12947 case XPATH_OP_ROOT:
12948 xmlXPathRoot(ctxt);
12949 return (0);
12950 case XPATH_OP_NODE:
12951 if (op->ch1 != -1)
12952 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012953 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012954 if (op->ch2 != -1)
12955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012956 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012957 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12958 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012959 return (total);
12960 case XPATH_OP_RESET:
12961 if (op->ch1 != -1)
12962 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012963 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012964 if (op->ch2 != -1)
12965 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012966 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012967 ctxt->context->node = NULL;
12968 return (total);
12969 case XPATH_OP_COLLECT:{
12970 if (op->ch1 == -1)
12971 return (0);
12972
12973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012974 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012975
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012976 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012977 return (total);
12978 }
12979 case XPATH_OP_VALUE:
12980 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012981 xmlXPathCacheObjectCopy(ctxt->context,
12982 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012983 return (0);
12984 case XPATH_OP_SORT:
12985 if (op->ch1 != -1)
12986 total +=
12987 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12988 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012989 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012990 if ((ctxt->value != NULL)
12991 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012992 && (ctxt->value->nodesetval != NULL)
12993 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012994 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12995 return (total);
12996 default:
12997 return (xmlXPathCompOpEval(ctxt, op));
12998 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012999}
13000
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013001#ifdef XP_OPTIMIZED_FILTER_FIRST
13002static int
13003xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
13004 xmlXPathStepOpPtr op, xmlNodePtr * first)
13005{
13006 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013007 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013008 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013009 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013010 xmlNodeSetPtr oldset;
13011 xmlNodePtr oldnode;
13012 xmlDocPtr oldDoc;
13013 int i;
13014
13015 CHECK_ERROR0;
13016 comp = ctxt->comp;
13017 /*
13018 * Optimization for ()[last()] selection i.e. the last elem
13019 */
13020 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13021 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13022 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13023 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013024
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013025 if ((f != -1) &&
13026 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13027 (comp->steps[f].value5 == NULL) &&
13028 (comp->steps[f].value == 0) &&
13029 (comp->steps[f].value4 != NULL) &&
13030 (xmlStrEqual
13031 (comp->steps[f].value4, BAD_CAST "last"))) {
13032 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013033
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013034 total +=
13035 xmlXPathCompOpEvalLast(ctxt,
13036 &comp->steps[op->ch1],
13037 &last);
13038 CHECK_ERROR0;
13039 /*
13040 * The nodeset should be in document order,
13041 * Keep only the last value
13042 */
13043 if ((ctxt->value != NULL) &&
13044 (ctxt->value->type == XPATH_NODESET) &&
13045 (ctxt->value->nodesetval != NULL) &&
13046 (ctxt->value->nodesetval->nodeTab != NULL) &&
13047 (ctxt->value->nodesetval->nodeNr > 1)) {
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013048 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013049 *first = *(ctxt->value->nodesetval->nodeTab);
13050 }
13051 return (total);
13052 }
13053 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013054
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013055 if (op->ch1 != -1)
13056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13057 CHECK_ERROR0;
13058 if (op->ch2 == -1)
13059 return (total);
13060 if (ctxt->value == NULL)
13061 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013062
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013063#ifdef LIBXML_XPTR_ENABLED
13064 oldnode = ctxt->context->node;
13065 /*
13066 * Hum are we filtering the result of an XPointer expression
13067 */
13068 if (ctxt->value->type == XPATH_LOCATIONSET) {
13069 xmlXPathObjectPtr tmp = NULL;
13070 xmlLocationSetPtr newlocset = NULL;
13071 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013072
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013073 /*
13074 * Extract the old locset, and then evaluate the result of the
13075 * expression for all the element in the locset. use it to grow
13076 * up a new locset.
13077 */
13078 CHECK_TYPE0(XPATH_LOCATIONSET);
13079 obj = valuePop(ctxt);
13080 oldlocset = obj->user;
13081 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013082
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013083 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13084 ctxt->context->contextSize = 0;
13085 ctxt->context->proximityPosition = 0;
13086 if (op->ch2 != -1)
13087 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13088 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013089 if (res != NULL) {
13090 xmlXPathReleaseObject(ctxt->context, res);
13091 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013092 valuePush(ctxt, obj);
13093 CHECK_ERROR0;
13094 return (total);
13095 }
13096 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013097
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013098 for (i = 0; i < oldlocset->locNr; i++) {
13099 /*
13100 * Run the evaluation with a node list made of a
13101 * single item in the nodelocset.
13102 */
13103 ctxt->context->node = oldlocset->locTab[i]->user;
13104 ctxt->context->contextSize = oldlocset->locNr;
13105 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013106 if (tmp == NULL) {
13107 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13108 ctxt->context->node);
13109 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013110 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13111 ctxt->context->node) < 0) {
13112 ctxt->error = XPATH_MEMORY_ERROR;
13113 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013114 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013115 valuePush(ctxt, tmp);
13116 if (op->ch2 != -1)
13117 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13118 if (ctxt->error != XPATH_EXPRESSION_OK) {
13119 xmlXPathFreeObject(obj);
13120 return(0);
13121 }
13122 /*
13123 * The result of the evaluation need to be tested to
13124 * decided whether the filter succeeded or not
13125 */
13126 res = valuePop(ctxt);
13127 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13128 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013129 xmlXPathCacheObjectCopy(ctxt->context,
13130 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013131 }
13132 /*
13133 * Cleanup
13134 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013135 if (res != NULL) {
13136 xmlXPathReleaseObject(ctxt->context, res);
13137 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013138 if (ctxt->value == tmp) {
13139 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013140 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013141 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013142 * REVISIT TODO: Don't create a temporary nodeset
13143 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013144 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013145 /* OLD: xmlXPathFreeObject(res); */
13146 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013147 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013148 ctxt->context->node = NULL;
13149 /*
13150 * Only put the first node in the result, then leave.
13151 */
13152 if (newlocset->locNr > 0) {
13153 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13154 break;
13155 }
13156 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013157 if (tmp != NULL) {
13158 xmlXPathReleaseObject(ctxt->context, tmp);
13159 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013160 /*
13161 * The result is used as the new evaluation locset.
13162 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013163 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013164 ctxt->context->node = NULL;
13165 ctxt->context->contextSize = -1;
13166 ctxt->context->proximityPosition = -1;
13167 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13168 ctxt->context->node = oldnode;
13169 return (total);
13170 }
13171#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013172
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013173 /*
13174 * Extract the old set, and then evaluate the result of the
13175 * expression for all the element in the set. use it to grow
13176 * up a new set.
13177 */
13178 CHECK_TYPE0(XPATH_NODESET);
13179 obj = valuePop(ctxt);
13180 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013181
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013182 oldnode = ctxt->context->node;
13183 oldDoc = ctxt->context->doc;
13184 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013185
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013186 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13187 ctxt->context->contextSize = 0;
13188 ctxt->context->proximityPosition = 0;
13189 /* QUESTION TODO: Why was this code commented out?
13190 if (op->ch2 != -1)
13191 total +=
13192 xmlXPathCompOpEval(ctxt,
13193 &comp->steps[op->ch2]);
13194 CHECK_ERROR0;
13195 res = valuePop(ctxt);
13196 if (res != NULL)
13197 xmlXPathFreeObject(res);
13198 */
13199 valuePush(ctxt, obj);
13200 ctxt->context->node = oldnode;
13201 CHECK_ERROR0;
13202 } else {
13203 xmlNodeSetPtr newset;
13204 xmlXPathObjectPtr tmp = NULL;
13205 /*
13206 * Initialize the new set.
13207 * Also set the xpath document in case things like
13208 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013209 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013210 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013211 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013212
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013213 for (i = 0; i < oldset->nodeNr; i++) {
13214 /*
13215 * Run the evaluation with a node list made of
13216 * a single item in the nodeset.
13217 */
13218 ctxt->context->node = oldset->nodeTab[i];
13219 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13220 (oldset->nodeTab[i]->doc != NULL))
13221 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013222 if (tmp == NULL) {
13223 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13224 ctxt->context->node);
13225 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013226 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13227 ctxt->context->node) < 0) {
13228 ctxt->error = XPATH_MEMORY_ERROR;
13229 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013230 }
13231 valuePush(ctxt, tmp);
13232 ctxt->context->contextSize = oldset->nodeNr;
13233 ctxt->context->proximityPosition = i + 1;
13234 if (op->ch2 != -1)
13235 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13236 if (ctxt->error != XPATH_EXPRESSION_OK) {
13237 xmlXPathFreeNodeSet(newset);
13238 xmlXPathFreeObject(obj);
13239 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013240 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013241 /*
13242 * The result of the evaluation needs to be tested to
13243 * decide whether the filter succeeded or not
13244 */
13245 res = valuePop(ctxt);
13246 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013247 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13248 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013249 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013250 /*
13251 * Cleanup
13252 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013253 if (res != NULL) {
13254 xmlXPathReleaseObject(ctxt->context, res);
13255 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013256 if (ctxt->value == tmp) {
13257 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013258 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013259 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013260 * in order to avoid massive recreation inside this
13261 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013262 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013263 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013264 } else
13265 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013266 ctxt->context->node = NULL;
13267 /*
13268 * Only put the first node in the result, then leave.
13269 */
13270 if (newset->nodeNr > 0) {
13271 *first = *(newset->nodeTab);
13272 break;
13273 }
13274 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013275 if (tmp != NULL) {
13276 xmlXPathReleaseObject(ctxt->context, tmp);
13277 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013278 /*
13279 * The result is used as the new evaluation set.
13280 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013281 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013282 ctxt->context->node = NULL;
13283 ctxt->context->contextSize = -1;
13284 ctxt->context->proximityPosition = -1;
13285 /* may want to move this past the '}' later */
13286 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013287 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013288 }
13289 ctxt->context->node = oldnode;
13290 return(total);
13291}
13292#endif /* XP_OPTIMIZED_FILTER_FIRST */
13293
Owen Taylor3473f882001-02-23 17:55:21 +000013294/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013295 * xmlXPathCompOpEval:
13296 * @ctxt: the XPath parser context with the compiled expression
13297 * @op: an XPath compiled operation
13298 *
13299 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013300 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013301 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013302static int
13303xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13304{
13305 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013306 int equal, ret;
13307 xmlXPathCompExprPtr comp;
13308 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013309 xmlNodePtr bak;
13310 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013311 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013312 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013313
Daniel Veillard556c6682001-10-06 09:59:51 +000013314 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013315 comp = ctxt->comp;
13316 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013317 case XPATH_OP_END:
13318 return (0);
13319 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013320 bakd = ctxt->context->doc;
13321 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013322 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013323 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013324 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013325 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013326 xmlXPathBooleanFunction(ctxt, 1);
13327 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13328 return (total);
13329 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013330 ctxt->context->doc = bakd;
13331 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013332 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013333 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013334 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013335 if (ctxt->error) {
13336 xmlXPathFreeObject(arg2);
13337 return(0);
13338 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013339 xmlXPathBooleanFunction(ctxt, 1);
13340 arg1 = valuePop(ctxt);
13341 arg1->boolval &= arg2->boolval;
13342 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013343 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013344 return (total);
13345 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013346 bakd = ctxt->context->doc;
13347 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013348 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013349 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013350 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013351 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013352 xmlXPathBooleanFunction(ctxt, 1);
13353 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13354 return (total);
13355 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013356 ctxt->context->doc = bakd;
13357 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013358 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013359 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013360 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013361 if (ctxt->error) {
13362 xmlXPathFreeObject(arg2);
13363 return(0);
13364 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013365 xmlXPathBooleanFunction(ctxt, 1);
13366 arg1 = valuePop(ctxt);
13367 arg1->boolval |= arg2->boolval;
13368 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013369 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013370 return (total);
13371 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013372 bakd = ctxt->context->doc;
13373 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013374 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013375 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013376 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013377 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013378 ctxt->context->doc = bakd;
13379 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013380 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013381 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013382 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013383 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013384 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013385 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013386 else
13387 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013388 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013389 return (total);
13390 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013391 bakd = ctxt->context->doc;
13392 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013393 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013394 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013395 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013396 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013397 ctxt->context->doc = bakd;
13398 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013399 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013400 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013401 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013402 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013403 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013404 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013405 return (total);
13406 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013407 bakd = ctxt->context->doc;
13408 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013409 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013410 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013411 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013412 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013413 if (op->ch2 != -1) {
13414 ctxt->context->doc = bakd;
13415 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013416 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013417 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013418 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013419 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013420 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013421 if (op->value == 0)
13422 xmlXPathSubValues(ctxt);
13423 else if (op->value == 1)
13424 xmlXPathAddValues(ctxt);
13425 else if (op->value == 2)
13426 xmlXPathValueFlipSign(ctxt);
13427 else if (op->value == 3) {
13428 CAST_TO_NUMBER;
13429 CHECK_TYPE0(XPATH_NUMBER);
13430 }
13431 return (total);
13432 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013433 bakd = ctxt->context->doc;
13434 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013435 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013436 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013437 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013438 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013439 ctxt->context->doc = bakd;
13440 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013441 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013442 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013443 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013444 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013445 if (op->value == 0)
13446 xmlXPathMultValues(ctxt);
13447 else if (op->value == 1)
13448 xmlXPathDivValues(ctxt);
13449 else if (op->value == 2)
13450 xmlXPathModValues(ctxt);
13451 return (total);
13452 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013453 bakd = ctxt->context->doc;
13454 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013455 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013456 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013457 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013458 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013459 ctxt->context->doc = bakd;
13460 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013461 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013462 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013463 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013464 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013465
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013466 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013467 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013468 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13469 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13470 xmlXPathReleaseObject(ctxt->context, arg1);
13471 xmlXPathReleaseObject(ctxt->context, arg2);
13472 XP_ERROR0(XPATH_INVALID_TYPE);
13473 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013474
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013475 if ((arg1->nodesetval == NULL) ||
13476 ((arg2->nodesetval != NULL) &&
13477 (arg2->nodesetval->nodeNr != 0)))
13478 {
13479 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13480 arg2->nodesetval);
13481 }
13482
Daniel Veillardf06307e2001-07-03 10:35:50 +000013483 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013484 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013485 return (total);
13486 case XPATH_OP_ROOT:
13487 xmlXPathRoot(ctxt);
13488 return (total);
13489 case XPATH_OP_NODE:
13490 if (op->ch1 != -1)
13491 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013492 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013493 if (op->ch2 != -1)
13494 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013495 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013496 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13497 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013498 return (total);
13499 case XPATH_OP_RESET:
13500 if (op->ch1 != -1)
13501 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013502 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013503 if (op->ch2 != -1)
13504 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013505 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013506 ctxt->context->node = NULL;
13507 return (total);
13508 case XPATH_OP_COLLECT:{
13509 if (op->ch1 == -1)
13510 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013511
Daniel Veillardf06307e2001-07-03 10:35:50 +000013512 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013513 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013514
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013515 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013516 return (total);
13517 }
13518 case XPATH_OP_VALUE:
13519 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013520 xmlXPathCacheObjectCopy(ctxt->context,
13521 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013522 return (total);
13523 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013524 xmlXPathObjectPtr val;
13525
Daniel Veillardf06307e2001-07-03 10:35:50 +000013526 if (op->ch1 != -1)
13527 total +=
13528 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013529 if (op->value5 == NULL) {
13530 val = xmlXPathVariableLookup(ctxt->context, op->value4);
Nick Wellnhofer3157cf42017-09-20 16:13:29 +020013531 if (val == NULL)
13532 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard556c6682001-10-06 09:59:51 +000013533 valuePush(ctxt, val);
13534 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013535 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013536
Daniel Veillardf06307e2001-07-03 10:35:50 +000013537 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13538 if (URI == NULL) {
13539 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013540 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13541 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013542 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013543 return (total);
13544 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013545 val = xmlXPathVariableLookupNS(ctxt->context,
13546 op->value4, URI);
Nick Wellnhofer3157cf42017-09-20 16:13:29 +020013547 if (val == NULL)
13548 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard556c6682001-10-06 09:59:51 +000013549 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013550 }
13551 return (total);
13552 }
13553 case XPATH_OP_FUNCTION:{
13554 xmlXPathFunction func;
13555 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013556 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013557 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013558
Daniel Veillardf5048b32011-08-18 17:10:13 +080013559 frame = xmlXPathSetFrame(ctxt);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013560 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013561 total +=
13562 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013563 if (ctxt->error != XPATH_EXPRESSION_OK) {
13564 xmlXPathPopFrame(ctxt, frame);
13565 return (total);
13566 }
13567 }
13568 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013569 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013570 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013571 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013572 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013573 return (total);
13574 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013575 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013576 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13577 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013578 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013579 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013580 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013581 return (total);
13582 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013583 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013584 if (op->cache != NULL)
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013585 func = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013586 else {
13587 const xmlChar *URI = NULL;
13588
13589 if (op->value5 == NULL)
13590 func =
13591 xmlXPathFunctionLookup(ctxt->context,
13592 op->value4);
13593 else {
13594 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13595 if (URI == NULL) {
13596 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013597 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13598 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013599 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013600 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013601 return (total);
13602 }
13603 func = xmlXPathFunctionLookupNS(ctxt->context,
13604 op->value4, URI);
13605 }
13606 if (func == NULL) {
13607 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013608 "xmlXPathCompOpEval: function %s not found\n",
13609 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013610 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013611 }
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013612 op->cache = func;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013613 op->cacheURI = (void *) URI;
13614 }
13615 oldFunc = ctxt->context->function;
13616 oldFuncURI = ctxt->context->functionURI;
13617 ctxt->context->function = op->value4;
13618 ctxt->context->functionURI = op->cacheURI;
13619 func(ctxt, op->value);
13620 ctxt->context->function = oldFunc;
13621 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013622 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013623 return (total);
13624 }
13625 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013626 bakd = ctxt->context->doc;
13627 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013628 pp = ctxt->context->proximityPosition;
13629 cs = ctxt->context->contextSize;
Nick Wellnhofer07def302014-03-21 19:38:08 +010013630 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013631 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013632 ctxt->context->contextSize = cs;
13633 ctxt->context->proximityPosition = pp;
13634 ctxt->context->node = bak;
13635 ctxt->context->doc = bakd;
13636 CHECK_ERROR0;
13637 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013638 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013639 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013640 ctxt->context->contextSize = cs;
13641 ctxt->context->proximityPosition = pp;
13642 ctxt->context->node = bak;
13643 ctxt->context->doc = bakd;
William M. Brack72ee48d2003-12-30 08:30:19 +000013644 CHECK_ERROR0;
13645 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013646 return (total);
13647 case XPATH_OP_PREDICATE:
13648 case XPATH_OP_FILTER:{
13649 xmlXPathObjectPtr res;
13650 xmlXPathObjectPtr obj, tmp;
13651 xmlNodeSetPtr newset = NULL;
13652 xmlNodeSetPtr oldset;
13653 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013654 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013655 int i;
13656
13657 /*
13658 * Optimization for ()[1] selection i.e. the first elem
13659 */
13660 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013661#ifdef XP_OPTIMIZED_FILTER_FIRST
13662 /*
13663 * FILTER TODO: Can we assume that the inner processing
13664 * will result in an ordered list if we have an
13665 * XPATH_OP_FILTER?
13666 * What about an additional field or flag on
13667 * xmlXPathObject like @sorted ? This way we wouln'd need
13668 * to assume anything, so it would be more robust and
13669 * easier to optimize.
13670 */
13671 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13672 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13673#else
13674 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13675#endif
13676 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013677 xmlXPathObjectPtr val;
13678
13679 val = comp->steps[op->ch2].value4;
13680 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13681 (val->floatval == 1.0)) {
13682 xmlNodePtr first = NULL;
13683
13684 total +=
13685 xmlXPathCompOpEvalFirst(ctxt,
13686 &comp->steps[op->ch1],
13687 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013688 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013689 /*
13690 * The nodeset should be in document order,
13691 * Keep only the first value
13692 */
13693 if ((ctxt->value != NULL) &&
13694 (ctxt->value->type == XPATH_NODESET) &&
13695 (ctxt->value->nodesetval != NULL) &&
13696 (ctxt->value->nodesetval->nodeNr > 1))
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013697 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13698 1, 1);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013699 return (total);
13700 }
13701 }
13702 /*
13703 * Optimization for ()[last()] selection i.e. the last elem
13704 */
13705 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13706 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13707 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13708 int f = comp->steps[op->ch2].ch1;
13709
13710 if ((f != -1) &&
13711 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13712 (comp->steps[f].value5 == NULL) &&
13713 (comp->steps[f].value == 0) &&
13714 (comp->steps[f].value4 != NULL) &&
13715 (xmlStrEqual
13716 (comp->steps[f].value4, BAD_CAST "last"))) {
13717 xmlNodePtr last = NULL;
13718
13719 total +=
13720 xmlXPathCompOpEvalLast(ctxt,
13721 &comp->steps[op->ch1],
13722 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013723 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013724 /*
13725 * The nodeset should be in document order,
13726 * Keep only the last value
13727 */
13728 if ((ctxt->value != NULL) &&
13729 (ctxt->value->type == XPATH_NODESET) &&
13730 (ctxt->value->nodesetval != NULL) &&
13731 (ctxt->value->nodesetval->nodeTab != NULL) &&
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013732 (ctxt->value->nodesetval->nodeNr > 1))
13733 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013734 return (total);
13735 }
13736 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013737 /*
13738 * Process inner predicates first.
13739 * Example "index[parent::book][1]":
13740 * ...
13741 * PREDICATE <-- we are here "[1]"
13742 * PREDICATE <-- process "[parent::book]" first
13743 * SORT
13744 * COLLECT 'parent' 'name' 'node' book
13745 * NODE
13746 * ELEM Object is a number : 1
13747 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013748 if (op->ch1 != -1)
13749 total +=
13750 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013751 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013752 if (op->ch2 == -1)
13753 return (total);
13754 if (ctxt->value == NULL)
13755 return (total);
13756
13757 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013758
13759#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013760 /*
13761 * Hum are we filtering the result of an XPointer expression
13762 */
13763 if (ctxt->value->type == XPATH_LOCATIONSET) {
13764 xmlLocationSetPtr newlocset = NULL;
13765 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013766
Daniel Veillardf06307e2001-07-03 10:35:50 +000013767 /*
13768 * Extract the old locset, and then evaluate the result of the
13769 * expression for all the element in the locset. use it to grow
13770 * up a new locset.
13771 */
13772 CHECK_TYPE0(XPATH_LOCATIONSET);
13773 obj = valuePop(ctxt);
13774 oldlocset = obj->user;
13775 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013776
Daniel Veillardf06307e2001-07-03 10:35:50 +000013777 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13778 ctxt->context->contextSize = 0;
13779 ctxt->context->proximityPosition = 0;
13780 if (op->ch2 != -1)
13781 total +=
13782 xmlXPathCompOpEval(ctxt,
13783 &comp->steps[op->ch2]);
13784 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013785 if (res != NULL) {
13786 xmlXPathReleaseObject(ctxt->context, res);
13787 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013788 valuePush(ctxt, obj);
13789 CHECK_ERROR0;
13790 return (total);
13791 }
13792 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013793
Daniel Veillardf06307e2001-07-03 10:35:50 +000013794 for (i = 0; i < oldlocset->locNr; i++) {
13795 /*
13796 * Run the evaluation with a node list made of a
13797 * single item in the nodelocset.
13798 */
13799 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013800 ctxt->context->contextSize = oldlocset->locNr;
13801 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013802 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13803 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013804 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013805
Daniel Veillardf06307e2001-07-03 10:35:50 +000013806 if (op->ch2 != -1)
13807 total +=
13808 xmlXPathCompOpEval(ctxt,
13809 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013810 if (ctxt->error != XPATH_EXPRESSION_OK) {
13811 xmlXPathFreeObject(obj);
13812 return(0);
13813 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013814
Daniel Veillardf06307e2001-07-03 10:35:50 +000013815 /*
13816 * The result of the evaluation need to be tested to
13817 * decided whether the filter succeeded or not
13818 */
13819 res = valuePop(ctxt);
13820 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13821 xmlXPtrLocationSetAdd(newlocset,
13822 xmlXPathObjectCopy
13823 (oldlocset->locTab[i]));
13824 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013825
Daniel Veillardf06307e2001-07-03 10:35:50 +000013826 /*
13827 * Cleanup
13828 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013829 if (res != NULL) {
13830 xmlXPathReleaseObject(ctxt->context, res);
13831 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013832 if (ctxt->value == tmp) {
13833 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013834 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013835 }
13836
13837 ctxt->context->node = NULL;
13838 }
13839
13840 /*
13841 * The result is used as the new evaluation locset.
13842 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013843 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013844 ctxt->context->node = NULL;
13845 ctxt->context->contextSize = -1;
13846 ctxt->context->proximityPosition = -1;
13847 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13848 ctxt->context->node = oldnode;
13849 return (total);
13850 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013851#endif /* LIBXML_XPTR_ENABLED */
13852
Daniel Veillardf06307e2001-07-03 10:35:50 +000013853 /*
13854 * Extract the old set, and then evaluate the result of the
13855 * expression for all the element in the set. use it to grow
13856 * up a new set.
13857 */
13858 CHECK_TYPE0(XPATH_NODESET);
13859 obj = valuePop(ctxt);
13860 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013861
Daniel Veillardf06307e2001-07-03 10:35:50 +000013862 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013863 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013864 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013865
Daniel Veillardf06307e2001-07-03 10:35:50 +000013866 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13867 ctxt->context->contextSize = 0;
13868 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013869/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013870 if (op->ch2 != -1)
13871 total +=
13872 xmlXPathCompOpEval(ctxt,
13873 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013874 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013875 res = valuePop(ctxt);
13876 if (res != NULL)
13877 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013878*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013879 valuePush(ctxt, obj);
13880 ctxt->context->node = oldnode;
13881 CHECK_ERROR0;
13882 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013883 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013884 /*
13885 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013886 * Also set the xpath document in case things like
13887 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013888 */
13889 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013890 /*
13891 * SPEC XPath 1.0:
13892 * "For each node in the node-set to be filtered, the
13893 * PredicateExpr is evaluated with that node as the
13894 * context node, with the number of nodes in the
13895 * node-set as the context size, and with the proximity
13896 * position of the node in the node-set with respect to
13897 * the axis as the context position;"
13898 * @oldset is the node-set" to be filtered.
13899 *
13900 * SPEC XPath 1.0:
13901 * "only predicates change the context position and
13902 * context size (see [2.4 Predicates])."
13903 * Example:
13904 * node-set context pos
13905 * nA 1
13906 * nB 2
13907 * nC 3
13908 * After applying predicate [position() > 1] :
13909 * node-set context pos
13910 * nB 1
13911 * nC 2
13912 *
13913 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013914 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013915 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013916 for (i = 0; i < oldset->nodeNr; i++) {
13917 /*
13918 * Run the evaluation with a node list made of
13919 * a single item in the nodeset.
13920 */
13921 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013922 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13923 (oldset->nodeTab[i]->doc != NULL))
13924 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013925 if (tmp == NULL) {
13926 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13927 ctxt->context->node);
13928 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013929 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13930 ctxt->context->node) < 0) {
13931 ctxt->error = XPATH_MEMORY_ERROR;
13932 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013933 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013934 valuePush(ctxt, tmp);
13935 ctxt->context->contextSize = oldset->nodeNr;
13936 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013937 /*
13938 * Evaluate the predicate against the context node.
13939 * Can/should we optimize position() predicates
13940 * here (e.g. "[1]")?
13941 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013942 if (op->ch2 != -1)
13943 total +=
13944 xmlXPathCompOpEval(ctxt,
13945 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013946 if (ctxt->error != XPATH_EXPRESSION_OK) {
13947 xmlXPathFreeNodeSet(newset);
13948 xmlXPathFreeObject(obj);
13949 return(0);
13950 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013951
Daniel Veillardf06307e2001-07-03 10:35:50 +000013952 /*
William M. Brack08171912003-12-29 02:52:11 +000013953 * The result of the evaluation needs to be tested to
13954 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013955 */
13956 /*
13957 * OPTIMIZE TODO: Can we use
13958 * xmlXPathNodeSetAdd*Unique()* instead?
13959 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013960 res = valuePop(ctxt);
13961 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013962 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13963 < 0)
13964 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013965 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013966
Daniel Veillardf06307e2001-07-03 10:35:50 +000013967 /*
13968 * Cleanup
13969 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013970 if (res != NULL) {
13971 xmlXPathReleaseObject(ctxt->context, res);
13972 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013973 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013974 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013975 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013976 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013977 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013978 * in order to avoid massive recreation inside this
13979 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013980 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013981 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013982 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013983 ctxt->context->node = NULL;
13984 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013985 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013986 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013987 /*
13988 * The result is used as the new evaluation set.
13989 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013990 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013991 ctxt->context->node = NULL;
13992 ctxt->context->contextSize = -1;
13993 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013994 /* may want to move this past the '}' later */
13995 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013996 valuePush(ctxt,
13997 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013998 }
13999 ctxt->context->node = oldnode;
14000 return (total);
14001 }
14002 case XPATH_OP_SORT:
14003 if (op->ch1 != -1)
14004 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000014005 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014006 if ((ctxt->value != NULL) &&
14007 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000014008 (ctxt->value->nodesetval != NULL) &&
14009 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014010 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014011 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014012 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014013 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014014#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000014015 case XPATH_OP_RANGETO:{
14016 xmlXPathObjectPtr range;
14017 xmlXPathObjectPtr res, obj;
14018 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000014019 xmlLocationSetPtr newlocset = NULL;
14020 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014021 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000014022 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014023
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020014024 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014025 total +=
14026 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020014027 CHECK_ERROR0;
14028 }
14029 if (ctxt->value == NULL) {
14030 XP_ERROR0(XPATH_INVALID_OPERAND);
14031 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014032 if (op->ch2 == -1)
14033 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014034
William M. Brack08171912003-12-29 02:52:11 +000014035 if (ctxt->value->type == XPATH_LOCATIONSET) {
14036 /*
14037 * Extract the old locset, and then evaluate the result of the
14038 * expression for all the element in the locset. use it to grow
14039 * up a new locset.
14040 */
14041 CHECK_TYPE0(XPATH_LOCATIONSET);
14042 obj = valuePop(ctxt);
14043 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014044
William M. Brack08171912003-12-29 02:52:11 +000014045 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000014046 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000014047 ctxt->context->contextSize = 0;
14048 ctxt->context->proximityPosition = 0;
14049 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14050 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014051 if (res != NULL) {
14052 xmlXPathReleaseObject(ctxt->context, res);
14053 }
William M. Brack08171912003-12-29 02:52:11 +000014054 valuePush(ctxt, obj);
14055 CHECK_ERROR0;
14056 return (total);
14057 }
14058 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014059
William M. Brack08171912003-12-29 02:52:11 +000014060 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014061 /*
William M. Brack08171912003-12-29 02:52:11 +000014062 * Run the evaluation with a node list made of a
14063 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000014064 */
William M. Brackf7eb7942003-12-31 07:59:17 +000014065 ctxt->context->node = oldlocset->locTab[i]->user;
14066 ctxt->context->contextSize = oldlocset->locNr;
14067 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014068 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14069 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014070 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014071
Daniel Veillardf06307e2001-07-03 10:35:50 +000014072 if (op->ch2 != -1)
14073 total +=
14074 xmlXPathCompOpEval(ctxt,
14075 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014076 if (ctxt->error != XPATH_EXPRESSION_OK) {
14077 xmlXPathFreeObject(obj);
14078 return(0);
14079 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014080
Daniel Veillardf06307e2001-07-03 10:35:50 +000014081 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000014082 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014083 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000014084 (xmlLocationSetPtr)res->user;
14085 for (j=0; j<rloc->locNr; j++) {
14086 range = xmlXPtrNewRange(
14087 oldlocset->locTab[i]->user,
14088 oldlocset->locTab[i]->index,
14089 rloc->locTab[j]->user2,
14090 rloc->locTab[j]->index2);
14091 if (range != NULL) {
14092 xmlXPtrLocationSetAdd(newlocset, range);
14093 }
14094 }
14095 } else {
14096 range = xmlXPtrNewRangeNodeObject(
14097 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14098 if (range != NULL) {
14099 xmlXPtrLocationSetAdd(newlocset,range);
14100 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014101 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014102
Daniel Veillardf06307e2001-07-03 10:35:50 +000014103 /*
14104 * Cleanup
14105 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014106 if (res != NULL) {
14107 xmlXPathReleaseObject(ctxt->context, res);
14108 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014109 if (ctxt->value == tmp) {
14110 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014111 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014112 }
14113
14114 ctxt->context->node = NULL;
14115 }
William M. Brack72ee48d2003-12-30 08:30:19 +000014116 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000014117 CHECK_TYPE0(XPATH_NODESET);
14118 obj = valuePop(ctxt);
14119 oldset = obj->nodesetval;
14120 ctxt->context->node = NULL;
14121
14122 newlocset = xmlXPtrLocationSetCreate(NULL);
14123
14124 if (oldset != NULL) {
14125 for (i = 0; i < oldset->nodeNr; i++) {
14126 /*
14127 * Run the evaluation with a node list made of a single item
14128 * in the nodeset.
14129 */
14130 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014131 /*
14132 * OPTIMIZE TODO: Avoid recreation for every iteration.
14133 */
14134 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14135 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000014136 valuePush(ctxt, tmp);
14137
14138 if (op->ch2 != -1)
14139 total +=
14140 xmlXPathCompOpEval(ctxt,
14141 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014142 if (ctxt->error != XPATH_EXPRESSION_OK) {
14143 xmlXPathFreeObject(obj);
14144 return(0);
14145 }
William M. Brack08171912003-12-29 02:52:11 +000014146
William M. Brack08171912003-12-29 02:52:11 +000014147 res = valuePop(ctxt);
14148 range =
14149 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14150 res);
14151 if (range != NULL) {
14152 xmlXPtrLocationSetAdd(newlocset, range);
14153 }
14154
14155 /*
14156 * Cleanup
14157 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014158 if (res != NULL) {
14159 xmlXPathReleaseObject(ctxt->context, res);
14160 }
William M. Brack08171912003-12-29 02:52:11 +000014161 if (ctxt->value == tmp) {
14162 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014163 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000014164 }
14165
14166 ctxt->context->node = NULL;
14167 }
14168 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014169 }
14170
14171 /*
14172 * The result is used as the new evaluation set.
14173 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014174 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014175 ctxt->context->node = NULL;
14176 ctxt->context->contextSize = -1;
14177 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000014178 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014179 return (total);
14180 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014181#endif /* LIBXML_XPTR_ENABLED */
14182 }
14183 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000014184 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080014185 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014186 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014187}
14188
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014189/**
14190 * xmlXPathCompOpEvalToBoolean:
14191 * @ctxt: the XPath parser context
14192 *
14193 * Evaluates if the expression evaluates to true.
14194 *
14195 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14196 */
14197static int
14198xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014199 xmlXPathStepOpPtr op,
14200 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014201{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014202 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014203
14204start:
14205 /* comp = ctxt->comp; */
14206 switch (op->op) {
14207 case XPATH_OP_END:
14208 return (0);
14209 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014210 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014211 if (isPredicate)
14212 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14213 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014214 case XPATH_OP_SORT:
14215 /*
14216 * We don't need sorting for boolean results. Skip this one.
14217 */
14218 if (op->ch1 != -1) {
14219 op = &ctxt->comp->steps[op->ch1];
14220 goto start;
14221 }
14222 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014223 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014224 if (op->ch1 == -1)
14225 return(0);
14226
14227 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14228 if (ctxt->error != XPATH_EXPRESSION_OK)
14229 return(-1);
14230
14231 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14232 if (ctxt->error != XPATH_EXPRESSION_OK)
14233 return(-1);
14234
14235 resObj = valuePop(ctxt);
14236 if (resObj == NULL)
14237 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014238 break;
14239 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014240 /*
14241 * Fallback to call xmlXPathCompOpEval().
14242 */
14243 xmlXPathCompOpEval(ctxt, op);
14244 if (ctxt->error != XPATH_EXPRESSION_OK)
14245 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014246
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014247 resObj = valuePop(ctxt);
14248 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014249 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014250 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014251 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014252
14253 if (resObj) {
14254 int res;
14255
14256 if (resObj->type == XPATH_BOOLEAN) {
14257 res = resObj->boolval;
14258 } else if (isPredicate) {
14259 /*
14260 * For predicates a result of type "number" is handled
14261 * differently:
14262 * SPEC XPath 1.0:
14263 * "If the result is a number, the result will be converted
14264 * to true if the number is equal to the context position
14265 * and will be converted to false otherwise;"
14266 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014267 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014268 } else {
14269 res = xmlXPathCastToBoolean(resObj);
14270 }
14271 xmlXPathReleaseObject(ctxt->context, resObj);
14272 return(res);
14273 }
14274
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014275 return(0);
14276}
14277
Daniel Veillard56de87e2005-02-16 00:22:29 +000014278#ifdef XPATH_STREAMING
14279/**
14280 * xmlXPathRunStreamEval:
14281 * @ctxt: the XPath parser context with the compiled expression
14282 *
14283 * Evaluate the Precompiled Streamable XPath expression in the given context.
14284 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014285static int
14286xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14287 xmlXPathObjectPtr *resultSeq, int toBool)
14288{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014289 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014290 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014291 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014292 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014293 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014294 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014295
14296 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014297
14298 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014299 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014300 max_depth = xmlPatternMaxDepth(comp);
14301 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014302 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014303 if (max_depth == -2)
14304 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014305 min_depth = xmlPatternMinDepth(comp);
14306 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014307 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014308 from_root = xmlPatternFromRoot(comp);
14309 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014310 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014311#if 0
14312 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14313#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014314
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014315 if (! toBool) {
14316 if (resultSeq == NULL)
14317 return(-1);
14318 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14319 if (*resultSeq == NULL)
14320 return(-1);
14321 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014322
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014323 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014324 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014325 */
14326 if (min_depth == 0) {
14327 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014328 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014329 if (toBool)
14330 return(1);
14331 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014332 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014333 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014334 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014335 if (toBool)
14336 return(1);
14337 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014338 }
14339 }
14340 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014341 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014342 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014343
Daniel Veillard56de87e2005-02-16 00:22:29 +000014344 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014345 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014346 } else if (ctxt->node != NULL) {
14347 switch (ctxt->node->type) {
14348 case XML_ELEMENT_NODE:
14349 case XML_DOCUMENT_NODE:
14350 case XML_DOCUMENT_FRAG_NODE:
14351 case XML_HTML_DOCUMENT_NODE:
14352#ifdef LIBXML_DOCB_ENABLED
14353 case XML_DOCB_DOCUMENT_NODE:
14354#endif
14355 cur = ctxt->node;
14356 break;
14357 case XML_ATTRIBUTE_NODE:
14358 case XML_TEXT_NODE:
14359 case XML_CDATA_SECTION_NODE:
14360 case XML_ENTITY_REF_NODE:
14361 case XML_ENTITY_NODE:
14362 case XML_PI_NODE:
14363 case XML_COMMENT_NODE:
14364 case XML_NOTATION_NODE:
14365 case XML_DTD_NODE:
14366 case XML_DOCUMENT_TYPE_NODE:
14367 case XML_ELEMENT_DECL:
14368 case XML_ATTRIBUTE_DECL:
14369 case XML_ENTITY_DECL:
14370 case XML_NAMESPACE_DECL:
14371 case XML_XINCLUDE_START:
14372 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014373 break;
14374 }
14375 limit = cur;
14376 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014377 if (cur == NULL) {
14378 return(0);
14379 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014380
14381 patstream = xmlPatternGetStreamCtxt(comp);
14382 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014383 /*
14384 * QUESTION TODO: Is this an error?
14385 */
14386 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014387 }
14388
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014389 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014390
Daniel Veillard56de87e2005-02-16 00:22:29 +000014391 if (from_root) {
14392 ret = xmlStreamPush(patstream, NULL, NULL);
14393 if (ret < 0) {
14394 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014395 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014396 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014397 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014398 }
14399 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014400 depth = 0;
14401 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014402next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014403 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014404 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014405
14406 switch (cur->type) {
14407 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014408 case XML_TEXT_NODE:
14409 case XML_CDATA_SECTION_NODE:
14410 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014411 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014412 if (cur->type == XML_ELEMENT_NODE) {
14413 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014414 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014415 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014416 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14417 else
14418 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014419
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014420 if (ret < 0) {
14421 /* NOP. */
14422 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014423 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014424 goto return_1;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014425 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14426 < 0) {
14427 ctxt->lastError.domain = XML_FROM_XPATH;
14428 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14429 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014430 }
14431 if ((cur->children == NULL) || (depth >= max_depth)) {
14432 ret = xmlStreamPop(patstream);
14433 while (cur->next != NULL) {
14434 cur = cur->next;
14435 if ((cur->type != XML_ENTITY_DECL) &&
14436 (cur->type != XML_DTD_NODE))
14437 goto next_node;
14438 }
14439 }
14440 default:
14441 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014442 }
14443
Daniel Veillard56de87e2005-02-16 00:22:29 +000014444scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080014445 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014446 if ((cur->children != NULL) && (depth < max_depth)) {
14447 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014448 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014449 */
14450 if (cur->children->type != XML_ENTITY_DECL) {
14451 cur = cur->children;
14452 depth++;
14453 /*
14454 * Skip DTDs
14455 */
14456 if (cur->type != XML_DTD_NODE)
14457 continue;
14458 }
14459 }
14460
14461 if (cur == limit)
14462 break;
14463
14464 while (cur->next != NULL) {
14465 cur = cur->next;
14466 if ((cur->type != XML_ENTITY_DECL) &&
14467 (cur->type != XML_DTD_NODE))
14468 goto next_node;
14469 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014470
Daniel Veillard56de87e2005-02-16 00:22:29 +000014471 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014472 cur = cur->parent;
14473 depth--;
14474 if ((cur == NULL) || (cur == limit))
14475 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014476 if (cur->type == XML_ELEMENT_NODE) {
14477 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014478 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014479 ((cur->type == XML_TEXT_NODE) ||
14480 (cur->type == XML_CDATA_SECTION_NODE) ||
14481 (cur->type == XML_COMMENT_NODE) ||
14482 (cur->type == XML_PI_NODE)))
14483 {
14484 ret = xmlStreamPop(patstream);
14485 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014486 if (cur->next != NULL) {
14487 cur = cur->next;
14488 break;
14489 }
14490 } while (cur != NULL);
14491
14492 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014493
Daniel Veillard56de87e2005-02-16 00:22:29 +000014494done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014495
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014496#if 0
14497 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014498 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014499#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014500
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014501 if (patstream)
14502 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014503 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014504
14505return_1:
14506 if (patstream)
14507 xmlFreeStreamCtxt(patstream);
14508 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014509}
14510#endif /* XPATH_STREAMING */
14511
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014512/**
14513 * xmlXPathRunEval:
14514 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014515 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014516 *
14517 * Evaluate the Precompiled XPath expression in the given context.
14518 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014519static int
14520xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14521{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014522 xmlXPathCompExprPtr comp;
14523
14524 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014525 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014526
14527 if (ctxt->valueTab == NULL) {
14528 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014529 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014530 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14531 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014532 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014533 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014534 }
14535 ctxt->valueNr = 0;
14536 ctxt->valueMax = 10;
14537 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014538 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014539 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014540#ifdef XPATH_STREAMING
14541 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014542 int res;
14543
14544 if (toBool) {
14545 /*
14546 * Evaluation to boolean result.
14547 */
14548 res = xmlXPathRunStreamEval(ctxt->context,
14549 ctxt->comp->stream, NULL, 1);
14550 if (res != -1)
14551 return(res);
14552 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014553 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014554
14555 /*
14556 * Evaluation to a sequence.
14557 */
14558 res = xmlXPathRunStreamEval(ctxt->context,
14559 ctxt->comp->stream, &resObj, 0);
14560
14561 if ((res != -1) && (resObj != NULL)) {
14562 valuePush(ctxt, resObj);
14563 return(0);
14564 }
14565 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014566 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014567 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014568 /*
14569 * QUESTION TODO: This falls back to normal XPath evaluation
14570 * if res == -1. Is this intended?
14571 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014572 }
14573#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014574 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014575 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014576 xmlGenericError(xmlGenericErrorContext,
14577 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014578 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014579 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014580 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014581 return(xmlXPathCompOpEvalToBoolean(ctxt,
14582 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014583 else
14584 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14585
14586 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014587}
14588
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014589/************************************************************************
14590 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014591 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014592 * *
14593 ************************************************************************/
14594
14595/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014596 * xmlXPathEvalPredicate:
14597 * @ctxt: the XPath context
14598 * @res: the Predicate Expression evaluation result
14599 *
14600 * Evaluate a predicate result for the current node.
14601 * A PredicateExpr is evaluated by evaluating the Expr and converting
14602 * the result to a boolean. If the result is a number, the result will
14603 * be converted to true if the number is equal to the position of the
14604 * context node in the context node list (as returned by the position
14605 * function) and will be converted to false otherwise; if the result
14606 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014607 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014608 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014609 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014610 */
14611int
14612xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014613 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014614 switch (res->type) {
14615 case XPATH_BOOLEAN:
14616 return(res->boolval);
14617 case XPATH_NUMBER:
14618 return(res->floatval == ctxt->proximityPosition);
14619 case XPATH_NODESET:
14620 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014621 if (res->nodesetval == NULL)
14622 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014623 return(res->nodesetval->nodeNr != 0);
14624 case XPATH_STRING:
14625 return((res->stringval != NULL) &&
14626 (xmlStrlen(res->stringval) != 0));
14627 default:
14628 STRANGE
14629 }
14630 return(0);
14631}
14632
14633/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014634 * xmlXPathEvaluatePredicateResult:
14635 * @ctxt: the XPath Parser context
14636 * @res: the Predicate Expression evaluation result
14637 *
14638 * Evaluate a predicate result for the current node.
14639 * A PredicateExpr is evaluated by evaluating the Expr and converting
14640 * the result to a boolean. If the result is a number, the result will
14641 * be converted to true if the number is equal to the position of the
14642 * context node in the context node list (as returned by the position
14643 * function) and will be converted to false otherwise; if the result
14644 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014645 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014646 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014647 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014648 */
14649int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014650xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014651 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014652 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014653 switch (res->type) {
14654 case XPATH_BOOLEAN:
14655 return(res->boolval);
14656 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014657#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014658 return((res->floatval == ctxt->context->proximityPosition) &&
14659 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014660#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014661 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014662#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014663 case XPATH_NODESET:
14664 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014665 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014666 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014667 return(res->nodesetval->nodeNr != 0);
14668 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014669 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014670#ifdef LIBXML_XPTR_ENABLED
14671 case XPATH_LOCATIONSET:{
14672 xmlLocationSetPtr ptr = res->user;
14673 if (ptr == NULL)
14674 return(0);
14675 return (ptr->locNr != 0);
14676 }
14677#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014678 default:
14679 STRANGE
14680 }
14681 return(0);
14682}
14683
Daniel Veillard56de87e2005-02-16 00:22:29 +000014684#ifdef XPATH_STREAMING
14685/**
14686 * xmlXPathTryStreamCompile:
14687 * @ctxt: an XPath context
14688 * @str: the XPath expression
14689 *
14690 * Try to compile the XPath expression as a streamable subset.
14691 *
14692 * Returns the compiled expression or NULL if failed to compile.
14693 */
14694static xmlXPathCompExprPtr
14695xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14696 /*
14697 * Optimization: use streaming patterns when the XPath expression can
14698 * be compiled to a stream lookup
14699 */
14700 xmlPatternPtr stream;
14701 xmlXPathCompExprPtr comp;
14702 xmlDictPtr dict = NULL;
14703 const xmlChar **namespaces = NULL;
14704 xmlNsPtr ns;
14705 int i, j;
14706
14707 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14708 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014709 const xmlChar *tmp;
14710
14711 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014712 * We don't try to handle expressions using the verbose axis
14713 * specifiers ("::"), just the simplied form at this point.
14714 * Additionally, if there is no list of namespaces available and
14715 * there's a ":" in the expression, indicating a prefixed QName,
14716 * then we won't try to compile either. xmlPatterncompile() needs
14717 * to have a list of namespaces at compilation time in order to
14718 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014719 */
14720 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014721 if ((tmp != NULL) &&
14722 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014723 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014724
Daniel Veillard56de87e2005-02-16 00:22:29 +000014725 if (ctxt != NULL) {
14726 dict = ctxt->dict;
14727 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014728 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014729 if (namespaces == NULL) {
14730 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14731 return(NULL);
14732 }
14733 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14734 ns = ctxt->namespaces[j];
14735 namespaces[i++] = ns->href;
14736 namespaces[i++] = ns->prefix;
14737 }
14738 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014739 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014740 }
14741 }
14742
William M. Brackea152c02005-06-09 18:12:28 +000014743 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14744 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014745 if (namespaces != NULL) {
14746 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014747 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014748 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14749 comp = xmlXPathNewCompExpr();
14750 if (comp == NULL) {
14751 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14752 return(NULL);
14753 }
14754 comp->stream = stream;
14755 comp->dict = dict;
14756 if (comp->dict)
14757 xmlDictReference(comp->dict);
14758 return(comp);
14759 }
14760 xmlFreePattern(stream);
14761 }
14762 return(NULL);
14763}
14764#endif /* XPATH_STREAMING */
14765
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014766static void
Nick Wellnhofer62270532012-08-19 19:42:38 +020014767xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014768{
14769 /*
14770 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14771 * internal representation.
14772 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014773
Nick Wellnhoferb4bcba22013-08-05 00:15:11 +020014774 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14775 (op->ch1 != -1) &&
14776 (op->ch2 == -1 /* no predicate */))
Nick Wellnhofer62270532012-08-19 19:42:38 +020014777 {
14778 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14779
14780 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14781 ((xmlXPathAxisVal) prevop->value ==
14782 AXIS_DESCENDANT_OR_SELF) &&
14783 (prevop->ch2 == -1) &&
14784 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14785 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14786 {
14787 /*
14788 * This is a "descendant-or-self::node()" without predicates.
14789 * Try to eliminate it.
14790 */
14791
14792 switch ((xmlXPathAxisVal) op->value) {
14793 case AXIS_CHILD:
14794 case AXIS_DESCENDANT:
14795 /*
14796 * Convert "descendant-or-self::node()/child::" or
14797 * "descendant-or-self::node()/descendant::" to
14798 * "descendant::"
14799 */
14800 op->ch1 = prevop->ch1;
14801 op->value = AXIS_DESCENDANT;
14802 break;
14803 case AXIS_SELF:
14804 case AXIS_DESCENDANT_OR_SELF:
14805 /*
14806 * Convert "descendant-or-self::node()/self::" or
14807 * "descendant-or-self::node()/descendant-or-self::" to
14808 * to "descendant-or-self::"
14809 */
14810 op->ch1 = prevop->ch1;
14811 op->value = AXIS_DESCENDANT_OR_SELF;
14812 break;
14813 default:
14814 break;
14815 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014816 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014817 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014818
Nick Wellnhofer839689a2016-04-27 18:00:12 +020014819 /* OP_VALUE has invalid ch1. */
14820 if (op->op == XPATH_OP_VALUE)
14821 return;
14822
Nick Wellnhofer62270532012-08-19 19:42:38 +020014823 /* Recurse */
14824 if (op->ch1 != -1)
14825 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014826 if (op->ch2 != -1)
Nick Wellnhofer62270532012-08-19 19:42:38 +020014827 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014828}
14829
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014830/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014831 * xmlXPathCtxtCompile:
14832 * @ctxt: an XPath context
14833 * @str: the XPath expression
14834 *
14835 * Compile an XPath expression
14836 *
14837 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14838 * the caller has to free the object.
14839 */
14840xmlXPathCompExprPtr
14841xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14842 xmlXPathParserContextPtr pctxt;
14843 xmlXPathCompExprPtr comp;
14844
Daniel Veillard56de87e2005-02-16 00:22:29 +000014845#ifdef XPATH_STREAMING
14846 comp = xmlXPathTryStreamCompile(ctxt, str);
14847 if (comp != NULL)
14848 return(comp);
14849#endif
14850
Daniel Veillard4773df22004-01-23 13:15:13 +000014851 xmlXPathInit();
14852
14853 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014854 if (pctxt == NULL)
14855 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014856 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014857
14858 if( pctxt->error != XPATH_EXPRESSION_OK )
14859 {
14860 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014861 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014862 }
14863
14864 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014865 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014866 * aleksey: in some cases this line prints *second* error message
14867 * (see bug #78858) and probably this should be fixed.
14868 * However, we are not sure that all error messages are printed
14869 * out in other places. It's not critical so we leave it as-is for now
14870 */
14871 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14872 comp = NULL;
14873 } else {
14874 comp = pctxt->comp;
14875 pctxt->comp = NULL;
14876 }
14877 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014878
Daniel Veillard4773df22004-01-23 13:15:13 +000014879 if (comp != NULL) {
14880 comp->expr = xmlStrdup(str);
14881#ifdef DEBUG_EVAL_COUNTS
14882 comp->string = xmlStrdup(str);
14883 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014884#endif
Nick Wellnhofer62270532012-08-19 19:42:38 +020014885 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14886 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014887 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014888 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014889 return(comp);
14890}
14891
14892/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014893 * xmlXPathCompile:
14894 * @str: the XPath expression
14895 *
14896 * Compile an XPath expression
14897 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014898 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014899 * the caller has to free the object.
14900 */
14901xmlXPathCompExprPtr
14902xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014903 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014904}
14905
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014906/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014907 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014908 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014909 * @ctxt: the XPath context
14910 * @resObj: the resulting XPath object or NULL
14911 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014912 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014913 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014914 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014915 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014916 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014917 * the caller has to free the object.
14918 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014919static int
14920xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14921 xmlXPathContextPtr ctxt,
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014922 xmlXPathObjectPtr *resObjPtr,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014923 int toBool)
14924{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014925 xmlXPathParserContextPtr pctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014926 xmlXPathObjectPtr resObj;
Daniel Veillard81463942001-10-16 12:34:39 +000014927#ifndef LIBXML_THREAD_ENABLED
14928 static int reentance = 0;
14929#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014930 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014931
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014932 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014933
14934 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014935 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014936 xmlXPathInit();
14937
Daniel Veillard81463942001-10-16 12:34:39 +000014938#ifndef LIBXML_THREAD_ENABLED
14939 reentance++;
14940 if (reentance > 1)
14941 xmlXPathDisableOptimizer = 1;
14942#endif
14943
Daniel Veillardf06307e2001-07-03 10:35:50 +000014944#ifdef DEBUG_EVAL_COUNTS
14945 comp->nb++;
14946 if ((comp->string != NULL) && (comp->nb > 100)) {
14947 fprintf(stderr, "100 x %s\n", comp->string);
14948 comp->nb = 0;
14949 }
14950#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014951 pctxt = xmlXPathCompParserContext(comp, ctxt);
14952 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014953
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014954 if (pctxt->error != XPATH_EXPRESSION_OK) {
14955 resObj = NULL;
14956 } else {
14957 resObj = valuePop(pctxt);
14958 if (resObj == NULL) {
Nick Wellnhofera07a4e92017-05-27 17:04:12 +020014959 if (!toBool)
14960 xmlGenericError(xmlGenericErrorContext,
14961 "xmlXPathCompiledEval: No result on the stack.\n");
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014962 } else if (pctxt->valueNr > 0) {
14963 xmlGenericError(xmlGenericErrorContext,
14964 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14965 pctxt->valueNr);
14966 }
Owen Taylor3473f882001-02-23 17:55:21 +000014967 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014968
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014969 if (resObjPtr)
14970 *resObjPtr = resObj;
14971 else
14972 xmlXPathReleaseObject(ctxt, resObj);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014973
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014974 pctxt->comp = NULL;
14975 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014976#ifndef LIBXML_THREAD_ENABLED
14977 reentance--;
14978#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014979
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014980 return(res);
14981}
14982
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014983/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014984 * xmlXPathCompiledEval:
14985 * @comp: the compiled XPath expression
14986 * @ctx: the XPath context
14987 *
14988 * Evaluate the Precompiled XPath expression in the given context.
14989 *
14990 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14991 * the caller has to free the object.
14992 */
14993xmlXPathObjectPtr
14994xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14995{
14996 xmlXPathObjectPtr res = NULL;
14997
14998 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14999 return(res);
15000}
15001
15002/**
15003 * xmlXPathCompiledEvalToBoolean:
15004 * @comp: the compiled XPath expression
15005 * @ctxt: the XPath context
15006 *
15007 * Applies the XPath boolean() function on the result of the given
15008 * compiled expression.
15009 *
15010 * Returns 1 if the expression evaluated to true, 0 if to false and
15011 * -1 in API and internal errors.
15012 */
15013int
15014xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
15015 xmlXPathContextPtr ctxt)
15016{
15017 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
15018}
15019
15020/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000015021 * xmlXPathEvalExpr:
15022 * @ctxt: the XPath Parser context
15023 *
15024 * Parse and evaluate an XPath expression in the given context,
15025 * then push the result on the context stack
15026 */
15027void
15028xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000015029#ifdef XPATH_STREAMING
15030 xmlXPathCompExprPtr comp;
15031#endif
15032
Daniel Veillarda82b1822004-11-08 16:24:57 +000015033 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015034
Daniel Veillard56de87e2005-02-16 00:22:29 +000015035#ifdef XPATH_STREAMING
15036 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15037 if (comp != NULL) {
15038 if (ctxt->comp != NULL)
15039 xmlXPathFreeCompExpr(ctxt->comp);
15040 ctxt->comp = comp;
Daniel Veillard56de87e2005-02-16 00:22:29 +000015041 } else
15042#endif
15043 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000015044 xmlXPathCompileExpr(ctxt, 1);
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020015045 CHECK_ERROR;
15046
15047 /* Check for trailing characters. */
15048 if (*ctxt->cur != 0)
15049 XP_ERROR(XPATH_EXPR_ERROR);
15050
15051 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
Nick Wellnhofer62270532012-08-19 19:42:38 +020015052 xmlXPathOptimizeExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000015053 &ctxt->comp->steps[ctxt->comp->last]);
Daniel Veillard56de87e2005-02-16 00:22:29 +000015054 }
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020015055
Daniel Veillard45490ae2008-07-29 09:13:19 +000015056 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000015057}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015058
15059/**
15060 * xmlXPathEval:
15061 * @str: the XPath expression
15062 * @ctx: the XPath context
15063 *
15064 * Evaluate the XPath Location Path in the given context.
15065 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000015066 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015067 * the caller has to free the object.
15068 */
15069xmlXPathObjectPtr
15070xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15071 xmlXPathParserContextPtr ctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020015072 xmlXPathObjectPtr res;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015073
William M. Brackf13f77f2004-11-12 16:03:48 +000015074 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015075
William M. Brackf13f77f2004-11-12 16:03:48 +000015076 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015077
15078 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000015079 if (ctxt == NULL)
15080 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015081 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015082
Nick Wellnhoferc8519702017-05-27 15:26:11 +020015083 if (ctxt->error != XPATH_EXPRESSION_OK) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015084 res = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015085 } else {
15086 res = valuePop(ctxt);
Nick Wellnhoferc8519702017-05-27 15:26:11 +020015087 if (res == NULL) {
15088 xmlGenericError(xmlGenericErrorContext,
15089 "xmlXPathCompiledEval: No result on the stack.\n");
15090 } else if (ctxt->valueNr > 0) {
15091 xmlGenericError(xmlGenericErrorContext,
15092 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
15093 ctxt->valueNr);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015094 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015095 }
15096
Owen Taylor3473f882001-02-23 17:55:21 +000015097 xmlXPathFreeParserContext(ctxt);
15098 return(res);
15099}
15100
15101/**
Alex Bligh28876af2013-03-23 17:23:27 +000015102 * xmlXPathSetContextNode:
15103 * @node: the node to to use as the context node
15104 * @ctx: the XPath context
15105 *
15106 * Sets 'node' as the context node. The node must be in the same
15107 * document as that associated with the context.
15108 *
15109 * Returns -1 in case of error or 0 if successful
15110 */
15111int
15112xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15113 if ((node == NULL) || (ctx == NULL))
15114 return(-1);
15115
15116 if (node->doc == ctx->doc) {
15117 ctx->node = node;
15118 return(0);
15119 }
15120 return(-1);
15121}
15122
15123/**
15124 * xmlXPathNodeEval:
15125 * @node: the node to to use as the context node
15126 * @str: the XPath expression
15127 * @ctx: the XPath context
15128 *
15129 * Evaluate the XPath Location Path in the given context. The node 'node'
15130 * is set as the context node. The context node is not restored.
15131 *
15132 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15133 * the caller has to free the object.
15134 */
15135xmlXPathObjectPtr
15136xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15137 if (str == NULL)
15138 return(NULL);
15139 if (xmlXPathSetContextNode(node, ctx) < 0)
15140 return(NULL);
15141 return(xmlXPathEval(str, ctx));
15142}
15143
15144/**
Owen Taylor3473f882001-02-23 17:55:21 +000015145 * xmlXPathEvalExpression:
15146 * @str: the XPath expression
15147 * @ctxt: the XPath context
15148 *
Daniel Veillarddbb828f2017-08-28 20:38:53 +020015149 * Alias for xmlXPathEval().
15150 *
15151 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15152 * the caller has to free the object.
Owen Taylor3473f882001-02-23 17:55:21 +000015153 */
15154xmlXPathObjectPtr
15155xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Nick Wellnhofer640a3682017-05-27 14:59:49 +020015156 return(xmlXPathEval(str, ctxt));
Owen Taylor3473f882001-02-23 17:55:21 +000015157}
15158
Daniel Veillard42766c02002-08-22 20:52:17 +000015159/************************************************************************
15160 * *
15161 * Extra functions not pertaining to the XPath spec *
15162 * *
15163 ************************************************************************/
15164/**
15165 * xmlXPathEscapeUriFunction:
15166 * @ctxt: the XPath Parser context
15167 * @nargs: the number of arguments
15168 *
15169 * Implement the escape-uri() XPath function
15170 * string escape-uri(string $str, bool $escape-reserved)
15171 *
15172 * This function applies the URI escaping rules defined in section 2 of [RFC
15173 * 2396] to the string supplied as $uri-part, which typically represents all
15174 * or part of a URI. The effect of the function is to replace any special
15175 * character in the string by an escape sequence of the form %xx%yy...,
15176 * where xxyy... is the hexadecimal representation of the octets used to
15177 * represent the character in UTF-8.
15178 *
15179 * The set of characters that are escaped depends on the setting of the
15180 * boolean argument $escape-reserved.
15181 *
15182 * If $escape-reserved is true, all characters are escaped other than lower
15183 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15184 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15185 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15186 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15187 * A-F).
15188 *
15189 * If $escape-reserved is false, the behavior differs in that characters
15190 * referred to in [RFC 2396] as reserved characters are not escaped. These
15191 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015192 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015193 * [RFC 2396] does not define whether escaped URIs should use lower case or
15194 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15195 * compared using string comparison functions, this function must always use
15196 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015197 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015198 * Generally, $escape-reserved should be set to true when escaping a string
15199 * that is to form a single part of a URI, and to false when escaping an
15200 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015201 *
15202 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015203 * utf-8 and then converted according to RFC 2396.
15204 *
15205 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015206 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015207 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15208 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15209 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15210 *
15211 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015212static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015213xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15214 xmlXPathObjectPtr str;
15215 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080015216 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000015217 xmlChar *cptr;
15218 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015219
Daniel Veillard42766c02002-08-22 20:52:17 +000015220 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015221
Daniel Veillard42766c02002-08-22 20:52:17 +000015222 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015223
Daniel Veillard42766c02002-08-22 20:52:17 +000015224 CAST_TO_STRING;
15225 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015226
Daniel Veillardade10f22012-07-12 09:43:27 +080015227 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015228
Daniel Veillard42766c02002-08-22 20:52:17 +000015229 escape[0] = '%';
15230 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015231
Daniel Veillard42766c02002-08-22 20:52:17 +000015232 if (target) {
15233 for (cptr = str->stringval; *cptr; cptr++) {
15234 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15235 (*cptr >= 'a' && *cptr <= 'z') ||
15236 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015237 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015238 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15239 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015240 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015241 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15242 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15243 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15244 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15245 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15246 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15247 (!escape_reserved &&
15248 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15249 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15250 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15251 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080015252 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000015253 } else {
15254 if ((*cptr >> 4) < 10)
15255 escape[1] = '0' + (*cptr >> 4);
15256 else
15257 escape[1] = 'A' - 10 + (*cptr >> 4);
15258 if ((*cptr & 0xF) < 10)
15259 escape[2] = '0' + (*cptr & 0xF);
15260 else
15261 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015262
Daniel Veillardade10f22012-07-12 09:43:27 +080015263 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000015264 }
15265 }
15266 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015267 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080015268 xmlBufContent(target)));
15269 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015270 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015271}
15272
Owen Taylor3473f882001-02-23 17:55:21 +000015273/**
15274 * xmlXPathRegisterAllFunctions:
15275 * @ctxt: the XPath context
15276 *
15277 * Registers all default XPath functions in this context
15278 */
15279void
15280xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15281{
15282 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15283 xmlXPathBooleanFunction);
15284 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15285 xmlXPathCeilingFunction);
15286 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15287 xmlXPathCountFunction);
15288 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15289 xmlXPathConcatFunction);
15290 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15291 xmlXPathContainsFunction);
15292 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15293 xmlXPathIdFunction);
15294 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15295 xmlXPathFalseFunction);
15296 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15297 xmlXPathFloorFunction);
15298 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15299 xmlXPathLastFunction);
15300 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15301 xmlXPathLangFunction);
15302 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15303 xmlXPathLocalNameFunction);
15304 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15305 xmlXPathNotFunction);
15306 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15307 xmlXPathNameFunction);
15308 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15309 xmlXPathNamespaceURIFunction);
15310 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15311 xmlXPathNormalizeFunction);
15312 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15313 xmlXPathNumberFunction);
15314 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15315 xmlXPathPositionFunction);
15316 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15317 xmlXPathRoundFunction);
15318 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15319 xmlXPathStringFunction);
15320 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15321 xmlXPathStringLengthFunction);
15322 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15323 xmlXPathStartsWithFunction);
15324 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15325 xmlXPathSubstringFunction);
15326 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15327 xmlXPathSubstringBeforeFunction);
15328 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15329 xmlXPathSubstringAfterFunction);
15330 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15331 xmlXPathSumFunction);
15332 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15333 xmlXPathTrueFunction);
15334 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15335 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015336
15337 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15338 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15339 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015340}
15341
15342#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015343#define bottom_xpath
15344#include "elfgcchack.h"