blob: 5e3bb9ff6401110ed5a22cbdaebf9108bd53334b [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
Elliott Hughes7fbecab2019-01-10 16:42:03 -08005 *
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
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200480#ifndef INFINITY
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800481#define INFINITY (DBL_MAX * DBL_MAX)
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200482#endif
483
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800484#ifndef NAN
485#define NAN (INFINITY / INFINITY)
486#endif
487
488double xmlXPathNAN;
489double xmlXPathPINF;
490double xmlXPathNINF;
Owen Taylor3473f882001-02-23 17:55:21 +0000491
Owen Taylor3473f882001-02-23 17:55:21 +0000492/**
493 * xmlXPathInit:
494 *
495 * Initialize the XPath environment
496 */
497void
498xmlXPathInit(void) {
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800499 xmlXPathNAN = NAN;
500 xmlXPathPINF = INFINITY;
501 xmlXPathNINF = -INFINITY;
Owen Taylor3473f882001-02-23 17:55:21 +0000502}
503
Daniel Veillardcda96922001-08-21 10:56:31 +0000504/**
505 * xmlXPathIsNaN:
506 * @val: a double value
507 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000508 * Returns 1 if the value is a NaN, 0 otherwise
509 */
510int
511xmlXPathIsNaN(double val) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200512#ifdef isnan
513 return isnan(val);
514#else
515 return !(val == val);
516#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000517}
518
519/**
520 * xmlXPathIsInf:
521 * @val: a double value
522 *
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200523 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
Daniel Veillardcda96922001-08-21 10:56:31 +0000524 */
525int
526xmlXPathIsInf(double val) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200527#ifdef isinf
Nick Wellnhoferddbb0752017-11-27 14:30:19 +0100528 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200529#else
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800530 if (val >= INFINITY)
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200531 return 1;
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800532 if (val <= -INFINITY)
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200533 return -1;
534 return 0;
535#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000536}
537
Daniel Veillard4432df22003-09-28 18:58:27 +0000538#endif /* SCHEMAS or XPATH */
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000539
Nick Wellnhofer8813f392017-09-21 00:11:26 +0200540#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000541
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000542/*
543 * TODO: when compatibility allows remove all "fake node libxslt" strings
544 * the test should just be name[0] = ' '
545 */
Daniel Veillard074f37e2008-09-01 13:38:22 +0000546#ifdef DEBUG_XPATH_EXPRESSION
547#define DEBUG_STEP
548#define DEBUG_EXPR
549#define DEBUG_EVAL_COUNTS
550#endif
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000551
552static xmlNs xmlXPathXMLNamespaceStruct = {
553 NULL,
554 XML_NAMESPACE_DECL,
555 XML_XML_NAMESPACE,
556 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000557 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000558 NULL
559};
560static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
561#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard45490ae2008-07-29 09:13:19 +0000562/*
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000563 * Optimizer is disabled only when threaded apps are detected while
564 * the library ain't compiled for thread safety.
565 */
566static int xmlXPathDisableOptimizer = 0;
567#endif
568
Owen Taylor3473f882001-02-23 17:55:21 +0000569/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000570 * *
571 * Error handling routines *
572 * *
573 ************************************************************************/
574
Daniel Veillard24505b02005-07-28 23:49:35 +0000575/**
576 * XP_ERRORNULL:
577 * @X: the error code
578 *
579 * Macro to raise an XPath error and return NULL.
580 */
581#define XP_ERRORNULL(X) \
582 { xmlXPathErr(ctxt, X); return(NULL); }
583
William M. Brack08171912003-12-29 02:52:11 +0000584/*
585 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
586 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000587static const char *xmlXPathErrorMessages[] = {
588 "Ok\n",
589 "Number encoding\n",
590 "Unfinished literal\n",
591 "Start of literal\n",
592 "Expected $ for variable reference\n",
593 "Undefined variable\n",
594 "Invalid predicate\n",
595 "Invalid expression\n",
596 "Missing closing curly brace\n",
597 "Unregistered function\n",
598 "Invalid operand\n",
599 "Invalid type\n",
600 "Invalid number of arguments\n",
601 "Invalid context size\n",
602 "Invalid context position\n",
603 "Memory allocation error\n",
604 "Syntax error\n",
605 "Resource error\n",
606 "Sub resource error\n",
607 "Undefined namespace prefix\n",
608 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000609 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000610 "Invalid or incomplete context\n",
Jan Pokorný75801652013-12-19 15:09:14 +0100611 "Stack usage error\n",
Daniel Veillard47881282012-09-07 14:24:50 +0800612 "Forbidden variable\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000613 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000614};
William M. Brackcd65bc92005-01-06 09:39:18 +0000615#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
616 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000617/**
618 * xmlXPathErrMemory:
619 * @ctxt: an XPath context
620 * @extra: extra informations
621 *
622 * Handle a redefinition of attribute error
623 */
624static void
625xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
626{
627 if (ctxt != NULL) {
628 if (extra) {
629 xmlChar buf[200];
630
631 xmlStrPrintf(buf, 200,
David Kilzer4472c3a2016-05-13 15:13:17 +0800632 "Memory allocation failed : %s\n",
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000633 extra);
634 ctxt->lastError.message = (char *) xmlStrdup(buf);
635 } else {
636 ctxt->lastError.message = (char *)
637 xmlStrdup(BAD_CAST "Memory allocation failed\n");
638 }
639 ctxt->lastError.domain = XML_FROM_XPATH;
640 ctxt->lastError.code = XML_ERR_NO_MEMORY;
641 if (ctxt->error != NULL)
642 ctxt->error(ctxt->userData, &ctxt->lastError);
643 } else {
644 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000645 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000646 NULL, NULL, XML_FROM_XPATH,
647 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
648 extra, NULL, NULL, 0, 0,
649 "Memory allocation failed : %s\n", extra);
650 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000651 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000652 NULL, NULL, XML_FROM_XPATH,
653 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
654 NULL, NULL, NULL, 0, 0,
655 "Memory allocation failed\n");
656 }
657}
658
659/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000660 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000661 * @ctxt: an XPath parser context
662 * @extra: extra informations
663 *
664 * Handle a redefinition of attribute error
665 */
666static void
667xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
668{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000669 if (ctxt == NULL)
670 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000671 else {
672 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000673 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000674 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000675}
676
677/**
678 * xmlXPathErr:
679 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000680 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000681 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000682 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000683 */
684void
685xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
686{
William M. Brackcd65bc92005-01-06 09:39:18 +0000687 if ((error < 0) || (error > MAXERRNO))
688 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000689 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000690 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000691 NULL, NULL, XML_FROM_XPATH,
692 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
693 XML_ERR_ERROR, NULL, 0,
694 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200695 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000696 return;
697 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000698 ctxt->error = error;
699 if (ctxt->context == NULL) {
700 __xmlRaiseError(NULL, NULL, NULL,
701 NULL, NULL, XML_FROM_XPATH,
702 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
703 XML_ERR_ERROR, NULL, 0,
704 (const char *) ctxt->base, NULL, NULL,
705 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200706 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000707 return;
708 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000709
710 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000711 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000712
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000713 ctxt->context->lastError.domain = XML_FROM_XPATH;
714 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
715 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000716 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000717 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
718 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
719 ctxt->context->lastError.node = ctxt->context->debugNode;
720 if (ctxt->context->error != NULL) {
721 ctxt->context->error(ctxt->context->userData,
722 &ctxt->context->lastError);
723 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000724 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000725 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
726 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
727 XML_ERR_ERROR, NULL, 0,
728 (const char *) ctxt->base, NULL, NULL,
729 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200730 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000731 }
732
733}
734
735/**
736 * xmlXPatherror:
737 * @ctxt: the XPath Parser context
738 * @file: the file name
739 * @line: the line number
740 * @no: the error number
741 *
742 * Formats an error message.
743 */
744void
745xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
746 int line ATTRIBUTE_UNUSED, int no) {
747 xmlXPathErr(ctxt, no);
748}
749
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000750/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000751 * *
752 * Utilities *
753 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000754 ************************************************************************/
755
756/**
757 * xsltPointerList:
758 *
759 * Pointer-list for various purposes.
760 */
761typedef struct _xmlPointerList xmlPointerList;
762typedef xmlPointerList *xmlPointerListPtr;
763struct _xmlPointerList {
764 void **items;
765 int number;
766 int size;
767};
768/*
769* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
770* and here, we should make the functions public.
771*/
772static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000773xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000774 void *item,
775 int initialSize)
776{
777 if (list->items == NULL) {
778 if (initialSize <= 0)
779 initialSize = 1;
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800780 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000781 if (list->items == NULL) {
782 xmlXPathErrMemory(NULL,
783 "xmlPointerListCreate: allocating item\n");
784 return(-1);
785 }
786 list->number = 0;
787 list->size = initialSize;
788 } else if (list->size <= list->number) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800789 if (list->size > 50000000) {
790 xmlXPathErrMemory(NULL,
791 "xmlPointerListAddSize: re-allocating item\n");
792 return(-1);
793 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000794 list->size *= 2;
795 list->items = (void **) xmlRealloc(list->items,
796 list->size * sizeof(void *));
797 if (list->items == NULL) {
798 xmlXPathErrMemory(NULL,
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800799 "xmlPointerListAddSize: re-allocating item\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000800 list->size = 0;
801 return(-1);
802 }
803 }
804 list->items[list->number++] = item;
805 return(0);
806}
807
808/**
809 * xsltPointerListCreate:
810 *
811 * Creates an xsltPointerList structure.
812 *
813 * Returns a xsltPointerList structure or NULL in case of an error.
814 */
815static xmlPointerListPtr
816xmlPointerListCreate(int initialSize)
817{
818 xmlPointerListPtr ret;
819
820 ret = xmlMalloc(sizeof(xmlPointerList));
821 if (ret == NULL) {
822 xmlXPathErrMemory(NULL,
823 "xmlPointerListCreate: allocating item\n");
824 return (NULL);
825 }
826 memset(ret, 0, sizeof(xmlPointerList));
827 if (initialSize > 0) {
828 xmlPointerListAddSize(ret, NULL, initialSize);
829 ret->number = 0;
830 }
831 return (ret);
832}
833
834/**
835 * xsltPointerListFree:
836 *
837 * Frees the xsltPointerList structure. This does not free
838 * the content of the list.
839 */
840static void
841xmlPointerListFree(xmlPointerListPtr list)
842{
843 if (list == NULL)
844 return;
845 if (list->items != NULL)
846 xmlFree(list->items);
847 xmlFree(list);
848}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000849
850/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000851 * *
852 * Parser Types *
853 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000854 ************************************************************************/
855
856/*
857 * Types are private:
858 */
859
860typedef enum {
861 XPATH_OP_END=0,
862 XPATH_OP_AND,
863 XPATH_OP_OR,
864 XPATH_OP_EQUAL,
865 XPATH_OP_CMP,
866 XPATH_OP_PLUS,
867 XPATH_OP_MULT,
868 XPATH_OP_UNION,
869 XPATH_OP_ROOT,
870 XPATH_OP_NODE,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000871 XPATH_OP_COLLECT,
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800872 XPATH_OP_VALUE, /* 11 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000873 XPATH_OP_VARIABLE,
874 XPATH_OP_FUNCTION,
875 XPATH_OP_ARG,
876 XPATH_OP_PREDICATE,
Elliott Hughes7fbecab2019-01-10 16:42:03 -0800877 XPATH_OP_FILTER, /* 16 */
878 XPATH_OP_SORT /* 17 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000879#ifdef LIBXML_XPTR_ENABLED
880 ,XPATH_OP_RANGETO
881#endif
882} xmlXPathOp;
883
884typedef enum {
885 AXIS_ANCESTOR = 1,
886 AXIS_ANCESTOR_OR_SELF,
887 AXIS_ATTRIBUTE,
888 AXIS_CHILD,
889 AXIS_DESCENDANT,
890 AXIS_DESCENDANT_OR_SELF,
891 AXIS_FOLLOWING,
892 AXIS_FOLLOWING_SIBLING,
893 AXIS_NAMESPACE,
894 AXIS_PARENT,
895 AXIS_PRECEDING,
896 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000897 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000898} xmlXPathAxisVal;
899
900typedef enum {
901 NODE_TEST_NONE = 0,
902 NODE_TEST_TYPE = 1,
903 NODE_TEST_PI = 2,
904 NODE_TEST_ALL = 3,
905 NODE_TEST_NS = 4,
906 NODE_TEST_NAME = 5
907} xmlXPathTestVal;
908
909typedef enum {
910 NODE_TYPE_NODE = 0,
911 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
912 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000913 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000914} xmlXPathTypeVal;
915
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000916typedef struct _xmlXPathStepOp xmlXPathStepOp;
917typedef xmlXPathStepOp *xmlXPathStepOpPtr;
918struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000919 xmlXPathOp op; /* The identifier of the operation */
920 int ch1; /* First child */
921 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000922 int value;
923 int value2;
924 int value3;
925 void *value4;
926 void *value5;
Nick Wellnhofer229d1f92016-08-22 13:21:57 +0200927 xmlXPathFunction cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000928 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000929};
930
931struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000932 int nbStep; /* Number of steps in this expression */
933 int maxStep; /* Maximum number of steps allocated */
934 xmlXPathStepOp *steps; /* ops for computation of this expression */
935 int last; /* index of last step in expression */
936 xmlChar *expr; /* the expression being computed */
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200937 xmlDictPtr dict; /* the dictionary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000938#ifdef DEBUG_EVAL_COUNTS
939 int nb;
940 xmlChar *string;
941#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000942#ifdef XPATH_STREAMING
943 xmlPatternPtr stream;
944#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000945};
946
947/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000948 * *
949 * Forward declarations *
950 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000951 ************************************************************************/
952static void
953xmlXPathFreeValueTree(xmlNodeSetPtr obj);
954static void
955xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
956static int
957xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
958 xmlXPathStepOpPtr op, xmlNodePtr *first);
959static int
960xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000961 xmlXPathStepOpPtr op,
962 int isPredicate);
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100963static void
964xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000965
966/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000967 * *
968 * Parser Type functions *
969 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000970 ************************************************************************/
971
972/**
973 * xmlXPathNewCompExpr:
974 *
975 * Create a new Xpath component
976 *
977 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
978 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000979static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000980xmlXPathNewCompExpr(void) {
981 xmlXPathCompExprPtr cur;
982
983 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
984 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000985 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000986 return(NULL);
987 }
988 memset(cur, 0, sizeof(xmlXPathCompExpr));
989 cur->maxStep = 10;
990 cur->nbStep = 0;
991 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
992 sizeof(xmlXPathStepOp));
993 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000994 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000995 xmlFree(cur);
996 return(NULL);
997 }
998 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
999 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +00001000#ifdef DEBUG_EVAL_COUNTS
1001 cur->nb = 0;
1002#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001003 return(cur);
1004}
1005
1006/**
1007 * xmlXPathFreeCompExpr:
1008 * @comp: an XPATH comp
1009 *
1010 * Free up the memory allocated by @comp
1011 */
1012void
Daniel Veillardf06307e2001-07-03 10:35:50 +00001013xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1014{
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001015 xmlXPathStepOpPtr op;
1016 int i;
1017
1018 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00001019 return;
Daniel Veillard4773df22004-01-23 13:15:13 +00001020 if (comp->dict == NULL) {
1021 for (i = 0; i < comp->nbStep; i++) {
1022 op = &comp->steps[i];
1023 if (op->value4 != NULL) {
1024 if (op->op == XPATH_OP_VALUE)
1025 xmlXPathFreeObject(op->value4);
1026 else
1027 xmlFree(op->value4);
1028 }
1029 if (op->value5 != NULL)
1030 xmlFree(op->value5);
1031 }
1032 } else {
1033 for (i = 0; i < comp->nbStep; i++) {
1034 op = &comp->steps[i];
1035 if (op->value4 != NULL) {
1036 if (op->op == XPATH_OP_VALUE)
1037 xmlXPathFreeObject(op->value4);
1038 }
1039 }
1040 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001041 }
1042 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00001043 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001044 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001045#ifdef DEBUG_EVAL_COUNTS
1046 if (comp->string != NULL) {
1047 xmlFree(comp->string);
1048 }
1049#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +00001050#ifdef XPATH_STREAMING
1051 if (comp->stream != NULL) {
1052 xmlFreePatternList(comp->stream);
1053 }
1054#endif
Daniel Veillard118aed72002-09-24 14:13:13 +00001055 if (comp->expr != NULL) {
1056 xmlFree(comp->expr);
1057 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001058
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001059 xmlFree(comp);
1060}
1061
1062/**
1063 * xmlXPathCompExprAdd:
1064 * @comp: the compiled expression
1065 * @ch1: first child index
1066 * @ch2: second child index
1067 * @op: an op
1068 * @value: the first int value
1069 * @value2: the second int value
1070 * @value3: the third int value
1071 * @value4: the first string value
1072 * @value5: the second string value
1073 *
William M. Brack08171912003-12-29 02:52:11 +00001074 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001075 *
1076 * Returns -1 in case of failure, the index otherwise
1077 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001078static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001079xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1080 xmlXPathOp op, int value,
1081 int value2, int value3, void *value4, void *value5) {
1082 if (comp->nbStep >= comp->maxStep) {
1083 xmlXPathStepOp *real;
1084
Daniel Veillardcd852ad2012-07-30 10:12:18 +08001085 if (comp->maxStep >= XPATH_MAX_STEPS) {
1086 xmlXPathErrMemory(NULL, "adding step\n");
1087 return(-1);
1088 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001089 comp->maxStep *= 2;
1090 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1091 comp->maxStep * sizeof(xmlXPathStepOp));
1092 if (real == NULL) {
1093 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001094 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001095 return(-1);
1096 }
1097 comp->steps = real;
1098 }
1099 comp->last = comp->nbStep;
1100 comp->steps[comp->nbStep].ch1 = ch1;
1101 comp->steps[comp->nbStep].ch2 = ch2;
1102 comp->steps[comp->nbStep].op = op;
1103 comp->steps[comp->nbStep].value = value;
1104 comp->steps[comp->nbStep].value2 = value2;
1105 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +00001106 if ((comp->dict != NULL) &&
1107 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1108 (op == XPATH_OP_COLLECT))) {
1109 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001110 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001111 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001112 xmlFree(value4);
1113 } else
1114 comp->steps[comp->nbStep].value4 = NULL;
1115 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001116 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001117 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001118 xmlFree(value5);
1119 } else
1120 comp->steps[comp->nbStep].value5 = NULL;
1121 } else {
1122 comp->steps[comp->nbStep].value4 = value4;
1123 comp->steps[comp->nbStep].value5 = value5;
1124 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00001125 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001126 return(comp->nbStep++);
1127}
1128
Daniel Veillardf06307e2001-07-03 10:35:50 +00001129/**
1130 * xmlXPathCompSwap:
1131 * @comp: the compiled expression
1132 * @op: operation index
1133 *
1134 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +00001135 */
1136static void
1137xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1138 int tmp;
1139
Daniel Veillardbc6f7592002-04-16 07:49:59 +00001140#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +00001141 /*
1142 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +00001143 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +00001144 * application
1145 */
1146 if (xmlXPathDisableOptimizer)
1147 return;
1148#endif
1149
Daniel Veillardf06307e2001-07-03 10:35:50 +00001150 tmp = op->ch1;
1151 op->ch1 = op->ch2;
1152 op->ch2 = tmp;
1153}
1154
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001155#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1156 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1157 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001158#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1159 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1160 (op), (val), (val2), (val3), (val4), (val5))
1161
Daniel Veillard45490ae2008-07-29 09:13:19 +00001162#define PUSH_LEAVE_EXPR(op, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001163xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1164
Daniel Veillard45490ae2008-07-29 09:13:19 +00001165#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001166xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1167
Daniel Veillard45490ae2008-07-29 09:13:19 +00001168#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +00001169xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1170 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001171
1172/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +00001173 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001174 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001175 * *
1176 ************************************************************************/
1177
1178/* #define XP_DEFAULT_CACHE_ON */
1179
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001180#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001181
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001182typedef struct _xmlXPathContextCache xmlXPathContextCache;
1183typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1184struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00001185 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1186 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1187 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1188 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1189 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001190 int maxNodeset;
1191 int maxString;
1192 int maxBoolean;
1193 int maxNumber;
1194 int maxMisc;
1195#ifdef XP_DEBUG_OBJ_USAGE
1196 int dbgCachedAll;
1197 int dbgCachedNodeset;
1198 int dbgCachedString;
1199 int dbgCachedBool;
1200 int dbgCachedNumber;
1201 int dbgCachedPoint;
1202 int dbgCachedRange;
1203 int dbgCachedLocset;
1204 int dbgCachedUsers;
1205 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001206 int dbgCachedUndefined;
1207
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001208
1209 int dbgReusedAll;
1210 int dbgReusedNodeset;
1211 int dbgReusedString;
1212 int dbgReusedBool;
1213 int dbgReusedNumber;
1214 int dbgReusedPoint;
1215 int dbgReusedRange;
1216 int dbgReusedLocset;
1217 int dbgReusedUsers;
1218 int dbgReusedXSLTTree;
1219 int dbgReusedUndefined;
1220
1221#endif
1222};
1223
1224/************************************************************************
1225 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001226 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +00001227 * *
1228 ************************************************************************/
1229
Daniel Veillard45490ae2008-07-29 09:13:19 +00001230#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +00001231 xmlGenericError(xmlGenericErrorContext, \
1232 "Internal error at %s:%d\n", \
1233 __FILE__, __LINE__);
1234
1235#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001236static void
1237xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001238 int i;
1239 char shift[100];
1240
1241 for (i = 0;((i < depth) && (i < 25));i++)
1242 shift[2 * i] = shift[2 * i + 1] = ' ';
1243 shift[2 * i] = shift[2 * i + 1] = 0;
1244 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001245 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001246 fprintf(output, "Node is NULL !\n");
1247 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001248
Owen Taylor3473f882001-02-23 17:55:21 +00001249 }
1250
1251 if ((cur->type == XML_DOCUMENT_NODE) ||
1252 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001253 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001254 fprintf(output, " /\n");
1255 } else if (cur->type == XML_ATTRIBUTE_NODE)
1256 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1257 else
1258 xmlDebugDumpOneNode(output, cur, depth);
1259}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001260static void
1261xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001262 xmlNodePtr tmp;
1263 int i;
1264 char shift[100];
1265
1266 for (i = 0;((i < depth) && (i < 25));i++)
1267 shift[2 * i] = shift[2 * i + 1] = ' ';
1268 shift[2 * i] = shift[2 * i + 1] = 0;
1269 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001270 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001271 fprintf(output, "Node is NULL !\n");
1272 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001273
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001274 }
1275
1276 while (cur != NULL) {
1277 tmp = cur;
1278 cur = cur->next;
1279 xmlDebugDumpOneNode(output, tmp, depth);
1280 }
1281}
Owen Taylor3473f882001-02-23 17:55:21 +00001282
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001283static void
1284xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001285 int i;
1286 char shift[100];
1287
1288 for (i = 0;((i < depth) && (i < 25));i++)
1289 shift[2 * i] = shift[2 * i + 1] = ' ';
1290 shift[2 * i] = shift[2 * i + 1] = 0;
1291
1292 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001293 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001294 fprintf(output, "NodeSet is NULL !\n");
1295 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001296
Owen Taylor3473f882001-02-23 17:55:21 +00001297 }
1298
Daniel Veillard911f49a2001-04-07 15:39:35 +00001299 if (cur != NULL) {
1300 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1301 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001302 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +00001303 fprintf(output, "%d", i + 1);
1304 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1305 }
Owen Taylor3473f882001-02-23 17:55:21 +00001306 }
1307}
1308
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001309static void
1310xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001311 int i;
1312 char shift[100];
1313
1314 for (i = 0;((i < depth) && (i < 25));i++)
1315 shift[2 * i] = shift[2 * i + 1] = ' ';
1316 shift[2 * i] = shift[2 * i + 1] = 0;
1317
1318 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001319 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001320 fprintf(output, "Value Tree is NULL !\n");
1321 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001322
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001323 }
1324
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001325 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001326 fprintf(output, "%d", i + 1);
1327 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1328}
Owen Taylor3473f882001-02-23 17:55:21 +00001329#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001330static void
1331xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001332 int i;
1333 char shift[100];
1334
1335 for (i = 0;((i < depth) && (i < 25));i++)
1336 shift[2 * i] = shift[2 * i + 1] = ' ';
1337 shift[2 * i] = shift[2 * i + 1] = 0;
1338
1339 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001340 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001341 fprintf(output, "LocationSet is NULL !\n");
1342 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001343
Owen Taylor3473f882001-02-23 17:55:21 +00001344 }
1345
1346 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001347 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001348 fprintf(output, "%d : ", i + 1);
1349 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1350 }
1351}
Daniel Veillard017b1082001-06-21 11:20:21 +00001352#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001353
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00001354/**
1355 * xmlXPathDebugDumpObject:
1356 * @output: the FILE * to dump the output
1357 * @cur: the object to inspect
1358 * @depth: indentation level
1359 *
1360 * Dump the content of the object for debugging purposes
1361 */
1362void
1363xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001364 int i;
1365 char shift[100];
1366
Daniel Veillarda82b1822004-11-08 16:24:57 +00001367 if (output == NULL) return;
1368
Owen Taylor3473f882001-02-23 17:55:21 +00001369 for (i = 0;((i < depth) && (i < 25));i++)
1370 shift[2 * i] = shift[2 * i + 1] = ' ';
1371 shift[2 * i] = shift[2 * i + 1] = 0;
1372
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001373
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001374 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001375
1376 if (cur == NULL) {
1377 fprintf(output, "Object is empty (NULL)\n");
1378 return;
1379 }
1380 switch(cur->type) {
1381 case XPATH_UNDEFINED:
1382 fprintf(output, "Object is uninitialized\n");
1383 break;
1384 case XPATH_NODESET:
1385 fprintf(output, "Object is a Node Set :\n");
1386 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1387 break;
1388 case XPATH_XSLT_TREE:
1389 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001390 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001391 break;
1392 case XPATH_BOOLEAN:
1393 fprintf(output, "Object is a Boolean : ");
1394 if (cur->boolval) fprintf(output, "true\n");
1395 else fprintf(output, "false\n");
1396 break;
1397 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001398 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001399 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001400 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001401 break;
1402 case -1:
1403 fprintf(output, "Object is a number : -Infinity\n");
1404 break;
1405 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001406 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001407 fprintf(output, "Object is a number : NaN\n");
Nick Wellnhofer8813f392017-09-21 00:11:26 +02001408 } else if (cur->floatval == 0) {
1409 /* Omit sign for negative zero. */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001410 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001411 } else {
1412 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1413 }
1414 }
Owen Taylor3473f882001-02-23 17:55:21 +00001415 break;
1416 case XPATH_STRING:
1417 fprintf(output, "Object is a string : ");
1418 xmlDebugDumpString(output, cur->stringval);
1419 fprintf(output, "\n");
1420 break;
1421 case XPATH_POINT:
1422 fprintf(output, "Object is a point : index %d in node", cur->index);
1423 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1424 fprintf(output, "\n");
1425 break;
1426 case XPATH_RANGE:
1427 if ((cur->user2 == NULL) ||
1428 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1429 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001430 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001431 if (cur->index >= 0)
1432 fprintf(output, "index %d in ", cur->index);
1433 fprintf(output, "node\n");
1434 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1435 depth + 1);
1436 } else {
1437 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001438 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001439 fprintf(output, "From ");
1440 if (cur->index >= 0)
1441 fprintf(output, "index %d in ", cur->index);
1442 fprintf(output, "node\n");
1443 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1444 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001445 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001446 fprintf(output, "To ");
1447 if (cur->index2 >= 0)
1448 fprintf(output, "index %d in ", cur->index2);
1449 fprintf(output, "node\n");
1450 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1451 depth + 1);
1452 fprintf(output, "\n");
1453 }
1454 break;
1455 case XPATH_LOCATIONSET:
1456#if defined(LIBXML_XPTR_ENABLED)
1457 fprintf(output, "Object is a Location Set:\n");
1458 xmlXPathDebugDumpLocationSet(output,
1459 (xmlLocationSetPtr) cur->user, depth);
1460#endif
1461 break;
1462 case XPATH_USERS:
1463 fprintf(output, "Object is user defined\n");
1464 break;
1465 }
1466}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001467
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001468static void
1469xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001470 xmlXPathStepOpPtr op, int depth) {
1471 int i;
1472 char shift[100];
1473
1474 for (i = 0;((i < depth) && (i < 25));i++)
1475 shift[2 * i] = shift[2 * i + 1] = ' ';
1476 shift[2 * i] = shift[2 * i + 1] = 0;
1477
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001478 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001479 if (op == NULL) {
1480 fprintf(output, "Step is NULL\n");
1481 return;
1482 }
1483 switch (op->op) {
1484 case XPATH_OP_END:
1485 fprintf(output, "END"); break;
1486 case XPATH_OP_AND:
1487 fprintf(output, "AND"); break;
1488 case XPATH_OP_OR:
1489 fprintf(output, "OR"); break;
1490 case XPATH_OP_EQUAL:
1491 if (op->value)
1492 fprintf(output, "EQUAL =");
1493 else
1494 fprintf(output, "EQUAL !=");
1495 break;
1496 case XPATH_OP_CMP:
1497 if (op->value)
1498 fprintf(output, "CMP <");
1499 else
1500 fprintf(output, "CMP >");
1501 if (!op->value2)
1502 fprintf(output, "=");
1503 break;
1504 case XPATH_OP_PLUS:
1505 if (op->value == 0)
1506 fprintf(output, "PLUS -");
1507 else if (op->value == 1)
1508 fprintf(output, "PLUS +");
1509 else if (op->value == 2)
1510 fprintf(output, "PLUS unary -");
1511 else if (op->value == 3)
1512 fprintf(output, "PLUS unary - -");
1513 break;
1514 case XPATH_OP_MULT:
1515 if (op->value == 0)
1516 fprintf(output, "MULT *");
1517 else if (op->value == 1)
1518 fprintf(output, "MULT div");
1519 else
1520 fprintf(output, "MULT mod");
1521 break;
1522 case XPATH_OP_UNION:
1523 fprintf(output, "UNION"); break;
1524 case XPATH_OP_ROOT:
1525 fprintf(output, "ROOT"); break;
1526 case XPATH_OP_NODE:
1527 fprintf(output, "NODE"); break;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001528 case XPATH_OP_SORT:
1529 fprintf(output, "SORT"); break;
1530 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001531 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1532 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1533 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001534 const xmlChar *prefix = op->value4;
1535 const xmlChar *name = op->value5;
1536
1537 fprintf(output, "COLLECT ");
1538 switch (axis) {
1539 case AXIS_ANCESTOR:
1540 fprintf(output, " 'ancestors' "); break;
1541 case AXIS_ANCESTOR_OR_SELF:
1542 fprintf(output, " 'ancestors-or-self' "); break;
1543 case AXIS_ATTRIBUTE:
1544 fprintf(output, " 'attributes' "); break;
1545 case AXIS_CHILD:
1546 fprintf(output, " 'child' "); break;
1547 case AXIS_DESCENDANT:
1548 fprintf(output, " 'descendant' "); break;
1549 case AXIS_DESCENDANT_OR_SELF:
1550 fprintf(output, " 'descendant-or-self' "); break;
1551 case AXIS_FOLLOWING:
1552 fprintf(output, " 'following' "); break;
1553 case AXIS_FOLLOWING_SIBLING:
1554 fprintf(output, " 'following-siblings' "); break;
1555 case AXIS_NAMESPACE:
1556 fprintf(output, " 'namespace' "); break;
1557 case AXIS_PARENT:
1558 fprintf(output, " 'parent' "); break;
1559 case AXIS_PRECEDING:
1560 fprintf(output, " 'preceding' "); break;
1561 case AXIS_PRECEDING_SIBLING:
1562 fprintf(output, " 'preceding-sibling' "); break;
1563 case AXIS_SELF:
1564 fprintf(output, " 'self' "); break;
1565 }
1566 switch (test) {
1567 case NODE_TEST_NONE:
1568 fprintf(output, "'none' "); break;
1569 case NODE_TEST_TYPE:
1570 fprintf(output, "'type' "); break;
1571 case NODE_TEST_PI:
1572 fprintf(output, "'PI' "); break;
1573 case NODE_TEST_ALL:
1574 fprintf(output, "'all' "); break;
1575 case NODE_TEST_NS:
1576 fprintf(output, "'namespace' "); break;
1577 case NODE_TEST_NAME:
1578 fprintf(output, "'name' "); break;
1579 }
1580 switch (type) {
1581 case NODE_TYPE_NODE:
1582 fprintf(output, "'node' "); break;
1583 case NODE_TYPE_COMMENT:
1584 fprintf(output, "'comment' "); break;
1585 case NODE_TYPE_TEXT:
1586 fprintf(output, "'text' "); break;
1587 case NODE_TYPE_PI:
1588 fprintf(output, "'PI' "); break;
1589 }
1590 if (prefix != NULL)
1591 fprintf(output, "%s:", prefix);
1592 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001593 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001594 break;
1595
1596 }
1597 case XPATH_OP_VALUE: {
1598 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1599
1600 fprintf(output, "ELEM ");
1601 xmlXPathDebugDumpObject(output, object, 0);
1602 goto finish;
1603 }
1604 case XPATH_OP_VARIABLE: {
1605 const xmlChar *prefix = op->value5;
1606 const xmlChar *name = op->value4;
1607
1608 if (prefix != NULL)
1609 fprintf(output, "VARIABLE %s:%s", prefix, name);
1610 else
1611 fprintf(output, "VARIABLE %s", name);
1612 break;
1613 }
1614 case XPATH_OP_FUNCTION: {
1615 int nbargs = op->value;
1616 const xmlChar *prefix = op->value5;
1617 const xmlChar *name = op->value4;
1618
1619 if (prefix != NULL)
1620 fprintf(output, "FUNCTION %s:%s(%d args)",
1621 prefix, name, nbargs);
1622 else
1623 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1624 break;
1625 }
1626 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1627 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001628 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001629#ifdef LIBXML_XPTR_ENABLED
1630 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1631#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001632 default:
1633 fprintf(output, "UNKNOWN %d\n", op->op); return;
1634 }
1635 fprintf(output, "\n");
1636finish:
1637 if (op->ch1 >= 0)
1638 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1639 if (op->ch2 >= 0)
1640 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1641}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001642
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001643/**
1644 * xmlXPathDebugDumpCompExpr:
1645 * @output: the FILE * for the output
1646 * @comp: the precompiled XPath expression
1647 * @depth: the indentation level.
1648 *
1649 * Dumps the tree of the compiled XPath expression.
1650 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001651void
1652xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1653 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001654 int i;
1655 char shift[100];
1656
Daniel Veillarda82b1822004-11-08 16:24:57 +00001657 if ((output == NULL) || (comp == NULL)) return;
1658
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001659 for (i = 0;((i < depth) && (i < 25));i++)
1660 shift[2 * i] = shift[2 * i + 1] = ' ';
1661 shift[2 * i] = shift[2 * i + 1] = 0;
1662
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001663 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001664
Nick Wellnhoferca8635b2017-09-07 15:46:12 +02001665#ifdef XPATH_STREAMING
1666 if (comp->stream) {
1667 fprintf(output, "Streaming Expression\n");
1668 } else
1669#endif
1670 {
1671 fprintf(output, "Compiled Expression : %d elements\n",
1672 comp->nbStep);
1673 i = comp->last;
1674 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1675 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001676}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001677
1678#ifdef XP_DEBUG_OBJ_USAGE
1679
1680/*
1681* XPath object usage related debugging variables.
1682*/
1683static int xmlXPathDebugObjCounterUndefined = 0;
1684static int xmlXPathDebugObjCounterNodeset = 0;
1685static int xmlXPathDebugObjCounterBool = 0;
1686static int xmlXPathDebugObjCounterNumber = 0;
1687static int xmlXPathDebugObjCounterString = 0;
1688static int xmlXPathDebugObjCounterPoint = 0;
1689static int xmlXPathDebugObjCounterRange = 0;
1690static int xmlXPathDebugObjCounterLocset = 0;
1691static int xmlXPathDebugObjCounterUsers = 0;
1692static int xmlXPathDebugObjCounterXSLTTree = 0;
1693static int xmlXPathDebugObjCounterAll = 0;
1694
1695static int xmlXPathDebugObjTotalUndefined = 0;
1696static int xmlXPathDebugObjTotalNodeset = 0;
1697static int xmlXPathDebugObjTotalBool = 0;
1698static int xmlXPathDebugObjTotalNumber = 0;
1699static int xmlXPathDebugObjTotalString = 0;
1700static int xmlXPathDebugObjTotalPoint = 0;
1701static int xmlXPathDebugObjTotalRange = 0;
1702static int xmlXPathDebugObjTotalLocset = 0;
1703static int xmlXPathDebugObjTotalUsers = 0;
1704static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001705static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001706
1707static int xmlXPathDebugObjMaxUndefined = 0;
1708static int xmlXPathDebugObjMaxNodeset = 0;
1709static int xmlXPathDebugObjMaxBool = 0;
1710static int xmlXPathDebugObjMaxNumber = 0;
1711static int xmlXPathDebugObjMaxString = 0;
1712static int xmlXPathDebugObjMaxPoint = 0;
1713static int xmlXPathDebugObjMaxRange = 0;
1714static int xmlXPathDebugObjMaxLocset = 0;
1715static int xmlXPathDebugObjMaxUsers = 0;
1716static int xmlXPathDebugObjMaxXSLTTree = 0;
1717static int xmlXPathDebugObjMaxAll = 0;
1718
1719/* REVISIT TODO: Make this static when committing */
1720static void
1721xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1722{
1723 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001724 if (ctxt->cache != NULL) {
1725 xmlXPathContextCachePtr cache =
1726 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001727
1728 cache->dbgCachedAll = 0;
1729 cache->dbgCachedNodeset = 0;
1730 cache->dbgCachedString = 0;
1731 cache->dbgCachedBool = 0;
1732 cache->dbgCachedNumber = 0;
1733 cache->dbgCachedPoint = 0;
1734 cache->dbgCachedRange = 0;
1735 cache->dbgCachedLocset = 0;
1736 cache->dbgCachedUsers = 0;
1737 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001738 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001739
1740 cache->dbgReusedAll = 0;
1741 cache->dbgReusedNodeset = 0;
1742 cache->dbgReusedString = 0;
1743 cache->dbgReusedBool = 0;
1744 cache->dbgReusedNumber = 0;
1745 cache->dbgReusedPoint = 0;
1746 cache->dbgReusedRange = 0;
1747 cache->dbgReusedLocset = 0;
1748 cache->dbgReusedUsers = 0;
1749 cache->dbgReusedXSLTTree = 0;
1750 cache->dbgReusedUndefined = 0;
1751 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001752 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001753
1754 xmlXPathDebugObjCounterUndefined = 0;
1755 xmlXPathDebugObjCounterNodeset = 0;
1756 xmlXPathDebugObjCounterBool = 0;
1757 xmlXPathDebugObjCounterNumber = 0;
1758 xmlXPathDebugObjCounterString = 0;
1759 xmlXPathDebugObjCounterPoint = 0;
1760 xmlXPathDebugObjCounterRange = 0;
1761 xmlXPathDebugObjCounterLocset = 0;
1762 xmlXPathDebugObjCounterUsers = 0;
1763 xmlXPathDebugObjCounterXSLTTree = 0;
1764 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001765
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001766 xmlXPathDebugObjTotalUndefined = 0;
1767 xmlXPathDebugObjTotalNodeset = 0;
1768 xmlXPathDebugObjTotalBool = 0;
1769 xmlXPathDebugObjTotalNumber = 0;
1770 xmlXPathDebugObjTotalString = 0;
1771 xmlXPathDebugObjTotalPoint = 0;
1772 xmlXPathDebugObjTotalRange = 0;
1773 xmlXPathDebugObjTotalLocset = 0;
1774 xmlXPathDebugObjTotalUsers = 0;
1775 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001776 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001777
1778 xmlXPathDebugObjMaxUndefined = 0;
1779 xmlXPathDebugObjMaxNodeset = 0;
1780 xmlXPathDebugObjMaxBool = 0;
1781 xmlXPathDebugObjMaxNumber = 0;
1782 xmlXPathDebugObjMaxString = 0;
1783 xmlXPathDebugObjMaxPoint = 0;
1784 xmlXPathDebugObjMaxRange = 0;
1785 xmlXPathDebugObjMaxLocset = 0;
1786 xmlXPathDebugObjMaxUsers = 0;
1787 xmlXPathDebugObjMaxXSLTTree = 0;
1788 xmlXPathDebugObjMaxAll = 0;
1789
1790}
1791
1792static void
1793xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1794 xmlXPathObjectType objType)
1795{
1796 int isCached = 0;
1797
1798 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001799 if (ctxt->cache != NULL) {
1800 xmlXPathContextCachePtr cache =
1801 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001802
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001803 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001804
1805 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001806 switch (objType) {
1807 case XPATH_UNDEFINED:
1808 cache->dbgReusedUndefined++;
1809 break;
1810 case XPATH_NODESET:
1811 cache->dbgReusedNodeset++;
1812 break;
1813 case XPATH_BOOLEAN:
1814 cache->dbgReusedBool++;
1815 break;
1816 case XPATH_NUMBER:
1817 cache->dbgReusedNumber++;
1818 break;
1819 case XPATH_STRING:
1820 cache->dbgReusedString++;
1821 break;
1822 case XPATH_POINT:
1823 cache->dbgReusedPoint++;
1824 break;
1825 case XPATH_RANGE:
1826 cache->dbgReusedRange++;
1827 break;
1828 case XPATH_LOCATIONSET:
1829 cache->dbgReusedLocset++;
1830 break;
1831 case XPATH_USERS:
1832 cache->dbgReusedUsers++;
1833 break;
1834 case XPATH_XSLT_TREE:
1835 cache->dbgReusedXSLTTree++;
1836 break;
1837 default:
1838 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001839 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001840 }
1841 }
1842
1843 switch (objType) {
1844 case XPATH_UNDEFINED:
1845 if (! isCached)
1846 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001847 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001848 if (xmlXPathDebugObjCounterUndefined >
1849 xmlXPathDebugObjMaxUndefined)
1850 xmlXPathDebugObjMaxUndefined =
1851 xmlXPathDebugObjCounterUndefined;
1852 break;
1853 case XPATH_NODESET:
1854 if (! isCached)
1855 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001856 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001857 if (xmlXPathDebugObjCounterNodeset >
1858 xmlXPathDebugObjMaxNodeset)
1859 xmlXPathDebugObjMaxNodeset =
1860 xmlXPathDebugObjCounterNodeset;
1861 break;
1862 case XPATH_BOOLEAN:
1863 if (! isCached)
1864 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001865 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001866 if (xmlXPathDebugObjCounterBool >
1867 xmlXPathDebugObjMaxBool)
1868 xmlXPathDebugObjMaxBool =
1869 xmlXPathDebugObjCounterBool;
1870 break;
1871 case XPATH_NUMBER:
1872 if (! isCached)
1873 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001874 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001875 if (xmlXPathDebugObjCounterNumber >
1876 xmlXPathDebugObjMaxNumber)
1877 xmlXPathDebugObjMaxNumber =
1878 xmlXPathDebugObjCounterNumber;
1879 break;
1880 case XPATH_STRING:
1881 if (! isCached)
1882 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001883 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001884 if (xmlXPathDebugObjCounterString >
1885 xmlXPathDebugObjMaxString)
1886 xmlXPathDebugObjMaxString =
1887 xmlXPathDebugObjCounterString;
1888 break;
1889 case XPATH_POINT:
1890 if (! isCached)
1891 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001892 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001893 if (xmlXPathDebugObjCounterPoint >
1894 xmlXPathDebugObjMaxPoint)
1895 xmlXPathDebugObjMaxPoint =
1896 xmlXPathDebugObjCounterPoint;
1897 break;
1898 case XPATH_RANGE:
1899 if (! isCached)
1900 xmlXPathDebugObjTotalRange++;
1901 xmlXPathDebugObjCounterRange++;
1902 if (xmlXPathDebugObjCounterRange >
1903 xmlXPathDebugObjMaxRange)
1904 xmlXPathDebugObjMaxRange =
1905 xmlXPathDebugObjCounterRange;
1906 break;
1907 case XPATH_LOCATIONSET:
1908 if (! isCached)
1909 xmlXPathDebugObjTotalLocset++;
1910 xmlXPathDebugObjCounterLocset++;
1911 if (xmlXPathDebugObjCounterLocset >
1912 xmlXPathDebugObjMaxLocset)
1913 xmlXPathDebugObjMaxLocset =
1914 xmlXPathDebugObjCounterLocset;
1915 break;
1916 case XPATH_USERS:
1917 if (! isCached)
1918 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001919 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001920 if (xmlXPathDebugObjCounterUsers >
1921 xmlXPathDebugObjMaxUsers)
1922 xmlXPathDebugObjMaxUsers =
1923 xmlXPathDebugObjCounterUsers;
1924 break;
1925 case XPATH_XSLT_TREE:
1926 if (! isCached)
1927 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001928 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001929 if (xmlXPathDebugObjCounterXSLTTree >
1930 xmlXPathDebugObjMaxXSLTTree)
1931 xmlXPathDebugObjMaxXSLTTree =
1932 xmlXPathDebugObjCounterXSLTTree;
1933 break;
1934 default:
1935 break;
1936 }
1937 if (! isCached)
1938 xmlXPathDebugObjTotalAll++;
1939 xmlXPathDebugObjCounterAll++;
1940 if (xmlXPathDebugObjCounterAll >
1941 xmlXPathDebugObjMaxAll)
1942 xmlXPathDebugObjMaxAll =
1943 xmlXPathDebugObjCounterAll;
1944}
1945
1946static void
1947xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1948 xmlXPathObjectType objType)
1949{
1950 int isCached = 0;
1951
1952 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001953 if (ctxt->cache != NULL) {
1954 xmlXPathContextCachePtr cache =
1955 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001956
Daniel Veillard45490ae2008-07-29 09:13:19 +00001957 isCached = 1;
1958
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001959 cache->dbgCachedAll++;
1960 switch (objType) {
1961 case XPATH_UNDEFINED:
1962 cache->dbgCachedUndefined++;
1963 break;
1964 case XPATH_NODESET:
1965 cache->dbgCachedNodeset++;
1966 break;
1967 case XPATH_BOOLEAN:
1968 cache->dbgCachedBool++;
1969 break;
1970 case XPATH_NUMBER:
1971 cache->dbgCachedNumber++;
1972 break;
1973 case XPATH_STRING:
1974 cache->dbgCachedString++;
1975 break;
1976 case XPATH_POINT:
1977 cache->dbgCachedPoint++;
1978 break;
1979 case XPATH_RANGE:
1980 cache->dbgCachedRange++;
1981 break;
1982 case XPATH_LOCATIONSET:
1983 cache->dbgCachedLocset++;
1984 break;
1985 case XPATH_USERS:
1986 cache->dbgCachedUsers++;
1987 break;
1988 case XPATH_XSLT_TREE:
1989 cache->dbgCachedXSLTTree++;
1990 break;
1991 default:
1992 break;
1993 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001994
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001995 }
1996 }
1997 switch (objType) {
1998 case XPATH_UNDEFINED:
1999 xmlXPathDebugObjCounterUndefined--;
2000 break;
2001 case XPATH_NODESET:
2002 xmlXPathDebugObjCounterNodeset--;
2003 break;
2004 case XPATH_BOOLEAN:
2005 xmlXPathDebugObjCounterBool--;
2006 break;
2007 case XPATH_NUMBER:
2008 xmlXPathDebugObjCounterNumber--;
2009 break;
2010 case XPATH_STRING:
2011 xmlXPathDebugObjCounterString--;
2012 break;
2013 case XPATH_POINT:
2014 xmlXPathDebugObjCounterPoint--;
2015 break;
2016 case XPATH_RANGE:
2017 xmlXPathDebugObjCounterRange--;
2018 break;
2019 case XPATH_LOCATIONSET:
2020 xmlXPathDebugObjCounterLocset--;
2021 break;
2022 case XPATH_USERS:
2023 xmlXPathDebugObjCounterUsers--;
2024 break;
2025 case XPATH_XSLT_TREE:
2026 xmlXPathDebugObjCounterXSLTTree--;
2027 break;
2028 default:
2029 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002030 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002031 xmlXPathDebugObjCounterAll--;
2032}
2033
2034/* REVISIT TODO: Make this static when committing */
2035static void
2036xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2037{
2038 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2039 reqXSLTTree, reqUndefined;
2040 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2041 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2042 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2043 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2044 int leftObjs = xmlXPathDebugObjCounterAll;
2045
2046 reqAll = xmlXPathDebugObjTotalAll;
2047 reqNodeset = xmlXPathDebugObjTotalNodeset;
2048 reqString = xmlXPathDebugObjTotalString;
2049 reqBool = xmlXPathDebugObjTotalBool;
2050 reqNumber = xmlXPathDebugObjTotalNumber;
2051 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2052 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002053
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002054 printf("# XPath object usage:\n");
2055
2056 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002057 if (ctxt->cache != NULL) {
2058 xmlXPathContextCachePtr cache =
2059 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002060
2061 reAll = cache->dbgReusedAll;
2062 reqAll += reAll;
2063 reNodeset = cache->dbgReusedNodeset;
2064 reqNodeset += reNodeset;
2065 reString = cache->dbgReusedString;
2066 reqString += reString;
2067 reBool = cache->dbgReusedBool;
2068 reqBool += reBool;
2069 reNumber = cache->dbgReusedNumber;
2070 reqNumber += reNumber;
2071 reXSLTTree = cache->dbgReusedXSLTTree;
2072 reqXSLTTree += reXSLTTree;
2073 reUndefined = cache->dbgReusedUndefined;
2074 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002075
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002076 caAll = cache->dbgCachedAll;
2077 caBool = cache->dbgCachedBool;
2078 caNodeset = cache->dbgCachedNodeset;
2079 caString = cache->dbgCachedString;
2080 caNumber = cache->dbgCachedNumber;
2081 caXSLTTree = cache->dbgCachedXSLTTree;
2082 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002083
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002084 if (cache->nodesetObjs)
2085 leftObjs -= cache->nodesetObjs->number;
2086 if (cache->stringObjs)
2087 leftObjs -= cache->stringObjs->number;
2088 if (cache->booleanObjs)
2089 leftObjs -= cache->booleanObjs->number;
2090 if (cache->numberObjs)
2091 leftObjs -= cache->numberObjs->number;
2092 if (cache->miscObjs)
2093 leftObjs -= cache->miscObjs->number;
2094 }
2095 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002096
2097 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002098 printf("# total : %d\n", reqAll);
2099 printf("# left : %d\n", leftObjs);
2100 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2101 printf("# reused : %d\n", reAll);
2102 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2103
2104 printf("# node-sets\n");
2105 printf("# total : %d\n", reqNodeset);
2106 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2107 printf("# reused : %d\n", reNodeset);
2108 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2109
2110 printf("# strings\n");
2111 printf("# total : %d\n", reqString);
2112 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2113 printf("# reused : %d\n", reString);
2114 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2115
2116 printf("# booleans\n");
2117 printf("# total : %d\n", reqBool);
2118 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2119 printf("# reused : %d\n", reBool);
2120 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2121
2122 printf("# numbers\n");
2123 printf("# total : %d\n", reqNumber);
2124 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2125 printf("# reused : %d\n", reNumber);
2126 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2127
2128 printf("# XSLT result tree fragments\n");
2129 printf("# total : %d\n", reqXSLTTree);
2130 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2131 printf("# reused : %d\n", reXSLTTree);
2132 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2133
2134 printf("# undefined\n");
2135 printf("# total : %d\n", reqUndefined);
2136 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2137 printf("# reused : %d\n", reUndefined);
2138 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2139
2140}
2141
2142#endif /* XP_DEBUG_OBJ_USAGE */
2143
Daniel Veillard017b1082001-06-21 11:20:21 +00002144#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002145
2146/************************************************************************
2147 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002148 * XPath object caching *
2149 * *
2150 ************************************************************************/
2151
2152/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002153 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002154 *
2155 * Create a new object cache
2156 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002157 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002158 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002159static xmlXPathContextCachePtr
2160xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002161{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002162 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002163
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002164 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002165 if (ret == NULL) {
2166 xmlXPathErrMemory(NULL, "creating object cache\n");
2167 return(NULL);
2168 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002169 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002170 ret->maxNodeset = 100;
2171 ret->maxString = 100;
2172 ret->maxBoolean = 100;
2173 ret->maxNumber = 100;
2174 ret->maxMisc = 100;
2175 return(ret);
2176}
2177
2178static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002179xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002180{
2181 int i;
2182 xmlXPathObjectPtr obj;
2183
2184 if (list == NULL)
2185 return;
2186
2187 for (i = 0; i < list->number; i++) {
2188 obj = list->items[i];
2189 /*
2190 * Note that it is already assured that we don't need to
2191 * look out for namespace nodes in the node-set.
2192 */
2193 if (obj->nodesetval != NULL) {
2194 if (obj->nodesetval->nodeTab != NULL)
2195 xmlFree(obj->nodesetval->nodeTab);
2196 xmlFree(obj->nodesetval);
2197 }
2198 xmlFree(obj);
2199#ifdef XP_DEBUG_OBJ_USAGE
2200 xmlXPathDebugObjCounterAll--;
2201#endif
2202 }
2203 xmlPointerListFree(list);
2204}
2205
2206static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002207xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002208{
2209 if (cache == NULL)
2210 return;
2211 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002212 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002213 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002214 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002215 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002216 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002217 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002218 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002219 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002220 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002221 xmlFree(cache);
2222}
2223
2224/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002225 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002226 *
2227 * @ctxt: the XPath context
2228 * @active: enables/disables (creates/frees) the cache
Daniel Veillard45490ae2008-07-29 09:13:19 +00002229 * @value: a value with semantics dependant on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002230 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002231 *
2232 * Creates/frees an object cache on the XPath context.
2233 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002234 * to be reused.
2235 * @options:
2236 * 0: This will set the XPath object caching:
2237 * @value:
2238 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002239 * to be cached per slot
2240 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002241 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002242 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002243 *
2244 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2245 */
2246int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002247xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2248 int active,
2249 int value,
2250 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002251{
2252 if (ctxt == NULL)
2253 return(-1);
2254 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002255 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002256
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002257 if (ctxt->cache == NULL) {
2258 ctxt->cache = xmlXPathNewCache();
2259 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002260 return(-1);
2261 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002262 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002263 if (options == 0) {
2264 if (value < 0)
2265 value = 100;
2266 cache->maxNodeset = value;
2267 cache->maxString = value;
2268 cache->maxNumber = value;
2269 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002270 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002271 }
2272 } else if (ctxt->cache != NULL) {
2273 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2274 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002275 }
2276 return(0);
2277}
2278
2279/**
2280 * xmlXPathCacheWrapNodeSet:
2281 * @ctxt: the XPath context
2282 * @val: the NodePtr value
2283 *
2284 * This is the cached version of xmlXPathWrapNodeSet().
2285 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2286 *
2287 * Returns the created or reused object.
2288 */
2289static xmlXPathObjectPtr
2290xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002291{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002292 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2293 xmlXPathContextCachePtr cache =
2294 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002295
2296 if ((cache->miscObjs != NULL) &&
2297 (cache->miscObjs->number != 0))
2298 {
2299 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002300
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002301 ret = (xmlXPathObjectPtr)
2302 cache->miscObjs->items[--cache->miscObjs->number];
2303 ret->type = XPATH_NODESET;
2304 ret->nodesetval = val;
2305#ifdef XP_DEBUG_OBJ_USAGE
2306 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2307#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00002308 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002309 }
2310 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002311
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002312 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00002313
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002314}
2315
2316/**
2317 * xmlXPathCacheWrapString:
2318 * @ctxt: the XPath context
2319 * @val: the xmlChar * value
2320 *
2321 * This is the cached version of xmlXPathWrapString().
2322 * Wraps the @val string into an XPath object.
2323 *
2324 * Returns the created or reused object.
2325 */
2326static xmlXPathObjectPtr
2327xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002328{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002329 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2330 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002331
2332 if ((cache->stringObjs != NULL) &&
2333 (cache->stringObjs->number != 0))
2334 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002335
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002336 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002337
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002338 ret = (xmlXPathObjectPtr)
2339 cache->stringObjs->items[--cache->stringObjs->number];
2340 ret->type = XPATH_STRING;
2341 ret->stringval = val;
2342#ifdef XP_DEBUG_OBJ_USAGE
2343 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2344#endif
2345 return(ret);
2346 } else if ((cache->miscObjs != NULL) &&
2347 (cache->miscObjs->number != 0))
2348 {
2349 xmlXPathObjectPtr ret;
2350 /*
2351 * Fallback to misc-cache.
2352 */
2353 ret = (xmlXPathObjectPtr)
2354 cache->miscObjs->items[--cache->miscObjs->number];
2355
2356 ret->type = XPATH_STRING;
2357 ret->stringval = val;
2358#ifdef XP_DEBUG_OBJ_USAGE
2359 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2360#endif
2361 return(ret);
2362 }
2363 }
2364 return(xmlXPathWrapString(val));
2365}
2366
2367/**
2368 * xmlXPathCacheNewNodeSet:
2369 * @ctxt: the XPath context
2370 * @val: the NodePtr value
2371 *
2372 * This is the cached version of xmlXPathNewNodeSet().
2373 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2374 * it with the single Node @val
2375 *
2376 * Returns the created or reused object.
2377 */
2378static xmlXPathObjectPtr
2379xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2380{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002381 if ((ctxt != NULL) && (ctxt->cache)) {
2382 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002383
2384 if ((cache->nodesetObjs != NULL) &&
2385 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002386 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002387 xmlXPathObjectPtr ret;
2388 /*
2389 * Use the nodset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002390 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002391 ret = (xmlXPathObjectPtr)
2392 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2393 ret->type = XPATH_NODESET;
2394 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002395 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002396 if ((ret->nodesetval->nodeMax == 0) ||
2397 (val->type == XML_NAMESPACE_DECL))
2398 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002399 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002400 } else {
2401 ret->nodesetval->nodeTab[0] = val;
2402 ret->nodesetval->nodeNr = 1;
2403 }
2404 }
2405#ifdef XP_DEBUG_OBJ_USAGE
2406 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2407#endif
2408 return(ret);
2409 } else if ((cache->miscObjs != NULL) &&
2410 (cache->miscObjs->number != 0))
2411 {
2412 xmlXPathObjectPtr ret;
2413 /*
2414 * Fallback to misc-cache.
2415 */
2416
2417 ret = (xmlXPathObjectPtr)
2418 cache->miscObjs->items[--cache->miscObjs->number];
2419
2420 ret->type = XPATH_NODESET;
2421 ret->boolval = 0;
2422 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08002423 if (ret->nodesetval == NULL) {
2424 ctxt->lastError.domain = XML_FROM_XPATH;
2425 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2426 return(NULL);
2427 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002428#ifdef XP_DEBUG_OBJ_USAGE
2429 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2430#endif
2431 return(ret);
2432 }
2433 }
2434 return(xmlXPathNewNodeSet(val));
2435}
2436
2437/**
2438 * xmlXPathCacheNewCString:
2439 * @ctxt: the XPath context
2440 * @val: the char * value
2441 *
2442 * This is the cached version of xmlXPathNewCString().
2443 * Acquire an xmlXPathObjectPtr of type string and of value @val
2444 *
2445 * Returns the created or reused object.
2446 */
2447static xmlXPathObjectPtr
2448xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002449{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002450 if ((ctxt != NULL) && (ctxt->cache)) {
2451 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002452
2453 if ((cache->stringObjs != NULL) &&
2454 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002455 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002456 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002457
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002458 ret = (xmlXPathObjectPtr)
2459 cache->stringObjs->items[--cache->stringObjs->number];
2460
2461 ret->type = XPATH_STRING;
2462 ret->stringval = xmlStrdup(BAD_CAST val);
2463#ifdef XP_DEBUG_OBJ_USAGE
2464 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2465#endif
2466 return(ret);
2467 } else if ((cache->miscObjs != NULL) &&
2468 (cache->miscObjs->number != 0))
2469 {
2470 xmlXPathObjectPtr ret;
2471
2472 ret = (xmlXPathObjectPtr)
2473 cache->miscObjs->items[--cache->miscObjs->number];
2474
2475 ret->type = XPATH_STRING;
2476 ret->stringval = xmlStrdup(BAD_CAST val);
2477#ifdef XP_DEBUG_OBJ_USAGE
2478 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2479#endif
2480 return(ret);
2481 }
2482 }
2483 return(xmlXPathNewCString(val));
2484}
2485
2486/**
2487 * xmlXPathCacheNewString:
2488 * @ctxt: the XPath context
2489 * @val: the xmlChar * value
2490 *
2491 * This is the cached version of xmlXPathNewString().
2492 * Acquire an xmlXPathObjectPtr of type string and of value @val
2493 *
2494 * Returns the created or reused object.
2495 */
2496static xmlXPathObjectPtr
2497xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002498{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002499 if ((ctxt != NULL) && (ctxt->cache)) {
2500 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002501
2502 if ((cache->stringObjs != NULL) &&
2503 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002504 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002505 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002506
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002507 ret = (xmlXPathObjectPtr)
2508 cache->stringObjs->items[--cache->stringObjs->number];
2509 ret->type = XPATH_STRING;
2510 if (val != NULL)
2511 ret->stringval = xmlStrdup(val);
2512 else
2513 ret->stringval = xmlStrdup((const xmlChar *)"");
2514#ifdef XP_DEBUG_OBJ_USAGE
2515 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2516#endif
2517 return(ret);
2518 } else if ((cache->miscObjs != NULL) &&
2519 (cache->miscObjs->number != 0))
2520 {
2521 xmlXPathObjectPtr ret;
2522
2523 ret = (xmlXPathObjectPtr)
2524 cache->miscObjs->items[--cache->miscObjs->number];
2525
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 }
2536 }
2537 return(xmlXPathNewString(val));
2538}
2539
2540/**
2541 * xmlXPathCacheNewBoolean:
2542 * @ctxt: the XPath context
2543 * @val: the boolean value
2544 *
2545 * This is the cached version of xmlXPathNewBoolean().
2546 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2547 *
2548 * Returns the created or reused object.
2549 */
2550static xmlXPathObjectPtr
2551xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002552{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002553 if ((ctxt != NULL) && (ctxt->cache)) {
2554 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002555
2556 if ((cache->booleanObjs != NULL) &&
2557 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002558 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002559 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002560
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002561 ret = (xmlXPathObjectPtr)
2562 cache->booleanObjs->items[--cache->booleanObjs->number];
2563 ret->type = XPATH_BOOLEAN;
2564 ret->boolval = (val != 0);
2565#ifdef XP_DEBUG_OBJ_USAGE
2566 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2567#endif
2568 return(ret);
2569 } else if ((cache->miscObjs != NULL) &&
2570 (cache->miscObjs->number != 0))
2571 {
2572 xmlXPathObjectPtr ret;
2573
2574 ret = (xmlXPathObjectPtr)
2575 cache->miscObjs->items[--cache->miscObjs->number];
2576
2577 ret->type = XPATH_BOOLEAN;
2578 ret->boolval = (val != 0);
2579#ifdef XP_DEBUG_OBJ_USAGE
2580 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2581#endif
2582 return(ret);
2583 }
2584 }
2585 return(xmlXPathNewBoolean(val));
2586}
2587
2588/**
2589 * xmlXPathCacheNewFloat:
2590 * @ctxt: the XPath context
2591 * @val: the double value
2592 *
2593 * This is the cached version of xmlXPathNewFloat().
2594 * Acquires an xmlXPathObjectPtr of type double and of value @val
2595 *
2596 * Returns the created or reused object.
2597 */
2598static xmlXPathObjectPtr
2599xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2600{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002601 if ((ctxt != NULL) && (ctxt->cache)) {
2602 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002603
2604 if ((cache->numberObjs != NULL) &&
2605 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002606 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002607 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002608
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002609 ret = (xmlXPathObjectPtr)
2610 cache->numberObjs->items[--cache->numberObjs->number];
2611 ret->type = XPATH_NUMBER;
2612 ret->floatval = val;
2613#ifdef XP_DEBUG_OBJ_USAGE
2614 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2615#endif
2616 return(ret);
2617 } else if ((cache->miscObjs != NULL) &&
2618 (cache->miscObjs->number != 0))
2619 {
2620 xmlXPathObjectPtr ret;
2621
2622 ret = (xmlXPathObjectPtr)
2623 cache->miscObjs->items[--cache->miscObjs->number];
2624
2625 ret->type = XPATH_NUMBER;
2626 ret->floatval = val;
2627#ifdef XP_DEBUG_OBJ_USAGE
2628 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2629#endif
2630 return(ret);
2631 }
2632 }
2633 return(xmlXPathNewFloat(val));
2634}
2635
2636/**
2637 * xmlXPathCacheConvertString:
2638 * @ctxt: the XPath context
2639 * @val: an XPath object
2640 *
2641 * This is the cached version of xmlXPathConvertString().
2642 * Converts an existing object to its string() equivalent
2643 *
2644 * Returns a created or reused object, the old one is freed (cached)
2645 * (or the operation is done directly on @val)
2646 */
2647
2648static xmlXPathObjectPtr
2649xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002650 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002651
2652 if (val == NULL)
2653 return(xmlXPathCacheNewCString(ctxt, ""));
2654
2655 switch (val->type) {
2656 case XPATH_UNDEFINED:
2657#ifdef DEBUG_EXPR
2658 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2659#endif
2660 break;
2661 case XPATH_NODESET:
2662 case XPATH_XSLT_TREE:
2663 res = xmlXPathCastNodeSetToString(val->nodesetval);
2664 break;
2665 case XPATH_STRING:
2666 return(val);
2667 case XPATH_BOOLEAN:
2668 res = xmlXPathCastBooleanToString(val->boolval);
2669 break;
2670 case XPATH_NUMBER:
2671 res = xmlXPathCastNumberToString(val->floatval);
2672 break;
2673 case XPATH_USERS:
2674 case XPATH_POINT:
2675 case XPATH_RANGE:
2676 case XPATH_LOCATIONSET:
2677 TODO;
2678 break;
2679 }
2680 xmlXPathReleaseObject(ctxt, val);
2681 if (res == NULL)
2682 return(xmlXPathCacheNewCString(ctxt, ""));
2683 return(xmlXPathCacheWrapString(ctxt, res));
2684}
2685
2686/**
2687 * xmlXPathCacheObjectCopy:
2688 * @ctxt: the XPath context
2689 * @val: the original object
2690 *
2691 * This is the cached version of xmlXPathObjectCopy().
2692 * Acquire a copy of a given object
2693 *
2694 * Returns a created or reused created object.
2695 */
2696static xmlXPathObjectPtr
2697xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2698{
2699 if (val == NULL)
2700 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002701
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002702 if (XP_HAS_CACHE(ctxt)) {
2703 switch (val->type) {
2704 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002705 return(xmlXPathCacheWrapNodeSet(ctxt,
2706 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002707 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002708 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002709 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002710 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002711 case XPATH_NUMBER:
2712 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2713 default:
2714 break;
2715 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002716 }
2717 return(xmlXPathObjectCopy(val));
2718}
2719
2720/**
2721 * xmlXPathCacheConvertBoolean:
2722 * @ctxt: the XPath context
2723 * @val: an XPath object
2724 *
2725 * This is the cached version of xmlXPathConvertBoolean().
2726 * Converts an existing object to its boolean() equivalent
2727 *
2728 * Returns a created or reused object, the old one is freed (or the operation
2729 * is done directly on @val)
2730 */
2731static xmlXPathObjectPtr
2732xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2733 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002734
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002735 if (val == NULL)
2736 return(xmlXPathCacheNewBoolean(ctxt, 0));
2737 if (val->type == XPATH_BOOLEAN)
2738 return(val);
2739 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2740 xmlXPathReleaseObject(ctxt, val);
2741 return(ret);
2742}
2743
2744/**
2745 * xmlXPathCacheConvertNumber:
2746 * @ctxt: the XPath context
2747 * @val: an XPath object
2748 *
2749 * This is the cached version of xmlXPathConvertNumber().
2750 * Converts an existing object to its number() equivalent
2751 *
2752 * Returns a created or reused object, the old one is freed (or the operation
2753 * is done directly on @val)
2754 */
2755static xmlXPathObjectPtr
2756xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2757 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002758
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002759 if (val == NULL)
2760 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2761 if (val->type == XPATH_NUMBER)
2762 return(val);
2763 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2764 xmlXPathReleaseObject(ctxt, val);
2765 return(ret);
2766}
2767
2768/************************************************************************
2769 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002770 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002771 * *
2772 ************************************************************************/
2773
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002774/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002775 * xmlXPathSetFrame:
2776 * @ctxt: an XPath parser context
2777 *
2778 * Set the callee evaluation frame
2779 *
2780 * Returns the previous frame value to be restored once done
2781 */
2782static int
2783xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2784 int ret;
2785
2786 if (ctxt == NULL)
2787 return(0);
2788 ret = ctxt->valueFrame;
2789 ctxt->valueFrame = ctxt->valueNr;
2790 return(ret);
2791}
2792
2793/**
2794 * xmlXPathPopFrame:
2795 * @ctxt: an XPath parser context
2796 * @frame: the previous frame value
2797 *
2798 * Remove the callee evaluation frame
2799 */
2800static void
2801xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2802 if (ctxt == NULL)
2803 return;
2804 if (ctxt->valueNr < ctxt->valueFrame) {
2805 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2806 }
2807 ctxt->valueFrame = frame;
2808}
2809
2810/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002811 * valuePop:
2812 * @ctxt: an XPath evaluation context
2813 *
2814 * Pops the top XPath object from the value stack
2815 *
2816 * Returns the XPath object just removed
2817 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002818xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002819valuePop(xmlXPathParserContextPtr ctxt)
2820{
2821 xmlXPathObjectPtr ret;
2822
Daniel Veillarda82b1822004-11-08 16:24:57 +00002823 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002824 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002825
2826 if (ctxt->valueNr <= ctxt->valueFrame) {
2827 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2828 return (NULL);
2829 }
2830
Daniel Veillard1c732d22002-11-30 11:22:59 +00002831 ctxt->valueNr--;
2832 if (ctxt->valueNr > 0)
2833 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2834 else
2835 ctxt->value = NULL;
2836 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002837 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002838 return (ret);
2839}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002840/**
2841 * valuePush:
2842 * @ctxt: an XPath evaluation context
2843 * @value: the XPath object
2844 *
2845 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002846 *
2847 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002848 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002849int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002850valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2851{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002852 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002853 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002854 xmlXPathObjectPtr *tmp;
2855
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002856 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2857 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2858 ctxt->error = XPATH_MEMORY_ERROR;
2859 return (0);
2860 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002861 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2862 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002863 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002864 if (tmp == NULL) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002865 xmlXPathErrMemory(NULL, "pushing value\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08002866 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002867 return (0);
2868 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002869 ctxt->valueMax *= 2;
2870 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002871 }
2872 ctxt->valueTab[ctxt->valueNr] = value;
2873 ctxt->value = value;
2874 return (ctxt->valueNr++);
2875}
Owen Taylor3473f882001-02-23 17:55:21 +00002876
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002877/**
2878 * xmlXPathPopBoolean:
2879 * @ctxt: an XPath parser context
2880 *
2881 * Pops a boolean from the stack, handling conversion if needed.
2882 * Check error with #xmlXPathCheckError.
2883 *
2884 * Returns the boolean
2885 */
2886int
2887xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2888 xmlXPathObjectPtr obj;
2889 int ret;
2890
2891 obj = valuePop(ctxt);
2892 if (obj == NULL) {
2893 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2894 return(0);
2895 }
William M. Brack08171912003-12-29 02:52:11 +00002896 if (obj->type != XPATH_BOOLEAN)
2897 ret = xmlXPathCastToBoolean(obj);
2898 else
2899 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002900 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002901 return(ret);
2902}
2903
2904/**
2905 * xmlXPathPopNumber:
2906 * @ctxt: an XPath parser context
2907 *
2908 * Pops a number from the stack, handling conversion if needed.
2909 * Check error with #xmlXPathCheckError.
2910 *
2911 * Returns the number
2912 */
2913double
2914xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2915 xmlXPathObjectPtr obj;
2916 double ret;
2917
2918 obj = valuePop(ctxt);
2919 if (obj == NULL) {
2920 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2921 return(0);
2922 }
William M. Brack08171912003-12-29 02:52:11 +00002923 if (obj->type != XPATH_NUMBER)
2924 ret = xmlXPathCastToNumber(obj);
2925 else
2926 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002927 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002928 return(ret);
2929}
2930
2931/**
2932 * xmlXPathPopString:
2933 * @ctxt: an XPath parser context
2934 *
2935 * Pops a string from the stack, handling conversion if needed.
2936 * Check error with #xmlXPathCheckError.
2937 *
2938 * Returns the string
2939 */
2940xmlChar *
2941xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2942 xmlXPathObjectPtr obj;
2943 xmlChar * ret;
2944
2945 obj = valuePop(ctxt);
2946 if (obj == NULL) {
2947 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2948 return(NULL);
2949 }
William M. Brack08171912003-12-29 02:52:11 +00002950 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002951 /* TODO: needs refactoring somewhere else */
2952 if (obj->stringval == ret)
2953 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002954 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002955 return(ret);
2956}
2957
2958/**
2959 * xmlXPathPopNodeSet:
2960 * @ctxt: an XPath parser context
2961 *
2962 * Pops a node-set from the stack, handling conversion if needed.
2963 * Check error with #xmlXPathCheckError.
2964 *
2965 * Returns the node-set
2966 */
2967xmlNodeSetPtr
2968xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2969 xmlXPathObjectPtr obj;
2970 xmlNodeSetPtr ret;
2971
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002972 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002973 if (ctxt->value == NULL) {
2974 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2975 return(NULL);
2976 }
2977 if (!xmlXPathStackIsNodeSet(ctxt)) {
2978 xmlXPathSetTypeError(ctxt);
2979 return(NULL);
2980 }
2981 obj = valuePop(ctxt);
2982 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002983#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002984 /* to fix memory leak of not clearing obj->user */
2985 if (obj->boolval && obj->user != NULL)
2986 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002987#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002988 obj->nodesetval = NULL;
2989 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002990 return(ret);
2991}
2992
2993/**
2994 * xmlXPathPopExternal:
2995 * @ctxt: an XPath parser context
2996 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002997 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002998 * Check error with #xmlXPathCheckError.
2999 *
3000 * Returns the object
3001 */
3002void *
3003xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3004 xmlXPathObjectPtr obj;
3005 void * ret;
3006
Daniel Veillarda82b1822004-11-08 16:24:57 +00003007 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003008 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3009 return(NULL);
3010 }
3011 if (ctxt->value->type != XPATH_USERS) {
3012 xmlXPathSetTypeError(ctxt);
3013 return(NULL);
3014 }
3015 obj = valuePop(ctxt);
3016 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003017 obj->user = NULL;
3018 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003019 return(ret);
3020}
3021
Owen Taylor3473f882001-02-23 17:55:21 +00003022/*
3023 * Macros for accessing the content. Those should be used only by the parser,
3024 * and not exported.
3025 *
3026 * Dirty macros, i.e. one need to make assumption on the context to use them
3027 *
3028 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3029 * CUR returns the current xmlChar value, i.e. a 8 bit value
3030 * in ISO-Latin or UTF-8.
3031 * This should be used internally by the parser
3032 * only to compare to ASCII values otherwise it would break when
3033 * running with UTF-8 encoding.
3034 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3035 * to compare on ASCII based substring.
3036 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3037 * strings within the parser.
3038 * CURRENT Returns the current char value, with the full decoding of
3039 * UTF-8 if we are using this mode. It returns an int.
3040 * NEXT Skip to the next character, this does the proper decoding
3041 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3042 * It returns the pointer to the current xmlChar.
3043 */
3044
3045#define CUR (*ctxt->cur)
3046#define SKIP(val) ctxt->cur += (val)
3047#define NXT(val) ctxt->cur[(val)]
3048#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00003049#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3050
3051#define COPY_BUF(l,b,i,v) \
3052 if (l == 1) b[i++] = (xmlChar) v; \
3053 else i += xmlCopyChar(l,&b[i],v)
3054
3055#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00003056
Daniel Veillard45490ae2008-07-29 09:13:19 +00003057#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00003058 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00003059
3060#define CURRENT (*ctxt->cur)
3061#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3062
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003063
3064#ifndef DBL_DIG
3065#define DBL_DIG 16
3066#endif
3067#ifndef DBL_EPSILON
3068#define DBL_EPSILON 1E-9
3069#endif
3070
3071#define UPPER_DOUBLE 1E9
3072#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00003073#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003074
3075#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00003076#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003077#define EXPONENT_DIGITS (3 + 2)
3078
3079/**
3080 * xmlXPathFormatNumber:
3081 * @number: number to format
3082 * @buffer: output buffer
3083 * @buffersize: size of output buffer
3084 *
3085 * Convert the number into a string representation.
3086 */
3087static void
3088xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3089{
Daniel Veillardcda96922001-08-21 10:56:31 +00003090 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003091 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003092 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003093 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003094 break;
3095 case -1:
3096 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003097 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003098 break;
3099 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003100 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003101 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003102 snprintf(buffer, buffersize, "NaN");
Nick Wellnhofer8813f392017-09-21 00:11:26 +02003103 } else if (number == 0) {
3104 /* Omit sign for negative zero. */
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003105 snprintf(buffer, buffersize, "0");
Nick Wellnhofer7482f412017-06-01 22:00:19 +02003106 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3107 (number == (int) number)) {
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003108 char work[30];
3109 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00003110 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003111
3112 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003113 if (value == 0) {
3114 *ptr++ = '0';
3115 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00003116 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003117 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00003118 while ((*cur) && (ptr - buffer < buffersize)) {
3119 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003120 }
3121 }
3122 if (ptr - buffer < buffersize) {
3123 *ptr = 0;
3124 } else if (buffersize > 0) {
3125 ptr--;
3126 *ptr = 0;
3127 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003128 } else {
William M. Brackca797882007-05-11 14:45:53 +00003129 /*
3130 For the dimension of work,
3131 DBL_DIG is number of significant digits
3132 EXPONENT is only needed for "scientific notation"
3133 3 is sign, decimal point, and terminating zero
3134 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3135 Note that this dimension is slightly (a few characters)
3136 larger than actually necessary.
3137 */
3138 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003139 int integer_place, fraction_place;
3140 char *ptr;
3141 char *after_fraction;
3142 double absolute_value;
3143 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003144
Bjorn Reese70a9da52001-04-21 16:57:29 +00003145 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003146
Bjorn Reese70a9da52001-04-21 16:57:29 +00003147 /*
3148 * First choose format - scientific or regular floating point.
3149 * In either case, result is in work, and after_fraction points
3150 * just past the fractional part.
3151 */
3152 if ( ((absolute_value > UPPER_DOUBLE) ||
3153 (absolute_value < LOWER_DOUBLE)) &&
3154 (absolute_value != 0.0) ) {
3155 /* Use scientific notation */
3156 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3157 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003158 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00003159 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00003160 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003161
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003162 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003163 else {
3164 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00003165 if (absolute_value > 0.0) {
3166 integer_place = (int)log10(absolute_value);
3167 if (integer_place > 0)
3168 fraction_place = DBL_DIG - integer_place - 1;
3169 else
3170 fraction_place = DBL_DIG - integer_place;
3171 } else {
3172 fraction_place = 1;
3173 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003174 size = snprintf(work, sizeof(work), "%0.*f",
3175 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003176 }
3177
Daniel Veillardb9e4d5b2013-07-22 13:21:31 +08003178 /* Remove leading spaces sometimes inserted by snprintf */
3179 while (work[0] == ' ') {
3180 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3181 size--;
3182 }
3183
Bjorn Reese70a9da52001-04-21 16:57:29 +00003184 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00003185 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003186 ptr = after_fraction;
3187 while (*(--ptr) == '0')
3188 ;
3189 if (*ptr != '.')
3190 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003191 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003192
3193 /* Finally copy result back to caller */
3194 size = strlen(work) + 1;
3195 if (size > buffersize) {
3196 work[buffersize - 1] = 0;
3197 size = buffersize;
3198 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003199 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003200 }
3201 break;
3202 }
3203}
3204
Owen Taylor3473f882001-02-23 17:55:21 +00003205
3206/************************************************************************
3207 * *
3208 * Routines to handle NodeSets *
3209 * *
3210 ************************************************************************/
3211
3212/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003213 * xmlXPathOrderDocElems:
3214 * @doc: an input document
3215 *
3216 * Call this routine to speed up XPath computation on static documents.
3217 * This stamps all the element nodes with the document order
3218 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00003219 * field, the value stored is actually - the node number (starting at -1)
3220 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003221 *
William M. Brack08171912003-12-29 02:52:11 +00003222 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003223 * of error.
3224 */
3225long
3226xmlXPathOrderDocElems(xmlDocPtr doc) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003227 ptrdiff_t count = 0;
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003228 xmlNodePtr cur;
3229
3230 if (doc == NULL)
3231 return(-1);
3232 cur = doc->children;
3233 while (cur != NULL) {
3234 if (cur->type == XML_ELEMENT_NODE) {
3235 cur->content = (void *) (-(++count));
3236 if (cur->children != NULL) {
3237 cur = cur->children;
3238 continue;
3239 }
3240 }
3241 if (cur->next != NULL) {
3242 cur = cur->next;
3243 continue;
3244 }
3245 do {
3246 cur = cur->parent;
3247 if (cur == NULL)
3248 break;
3249 if (cur == (xmlNodePtr) doc) {
3250 cur = NULL;
3251 break;
3252 }
3253 if (cur->next != NULL) {
3254 cur = cur->next;
3255 break;
3256 }
3257 } while (cur != NULL);
3258 }
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003259 return((long) count);
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003260}
3261
3262/**
Owen Taylor3473f882001-02-23 17:55:21 +00003263 * xmlXPathCmpNodes:
3264 * @node1: the first node
3265 * @node2: the second node
3266 *
3267 * Compare two nodes w.r.t document order
3268 *
3269 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00003270 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003271 */
3272int
3273xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3274 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003275 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003276 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003277 xmlNodePtr cur, root;
3278
3279 if ((node1 == NULL) || (node2 == NULL))
3280 return(-2);
3281 /*
3282 * a couple of optimizations which will avoid computations in most cases
3283 */
William M. Brackee0b9822007-03-07 08:15:01 +00003284 if (node1 == node2) /* trivial case */
3285 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00003286 if (node1->type == XML_ATTRIBUTE_NODE) {
3287 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003288 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003289 node1 = node1->parent;
3290 }
3291 if (node2->type == XML_ATTRIBUTE_NODE) {
3292 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003293 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003294 node2 = node2->parent;
3295 }
3296 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00003297 if (attr1 == attr2) {
3298 /* not required, but we keep attributes in order */
3299 if (attr1 != 0) {
3300 cur = attrNode2->prev;
3301 while (cur != NULL) {
3302 if (cur == attrNode1)
3303 return (1);
3304 cur = cur->prev;
3305 }
3306 return (-1);
3307 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003308 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00003309 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003310 if (attr2 == 1)
3311 return(1);
3312 return(-1);
3313 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003314 if ((node1->type == XML_NAMESPACE_DECL) ||
3315 (node2->type == XML_NAMESPACE_DECL))
3316 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003317 if (node1 == node2->prev)
3318 return(1);
3319 if (node1 == node2->next)
3320 return(-1);
3321
3322 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003323 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003324 */
3325 if ((node1->type == XML_ELEMENT_NODE) &&
3326 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003327 (0 > (ptrdiff_t) node1->content) &&
3328 (0 > (ptrdiff_t) node2->content) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003329 (node1->doc == node2->doc)) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003330 ptrdiff_t l1, l2;
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003331
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003332 l1 = -((ptrdiff_t) node1->content);
3333 l2 = -((ptrdiff_t) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003334 if (l1 < l2)
3335 return(1);
3336 if (l1 > l2)
3337 return(-1);
3338 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003339
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003340 /*
Owen Taylor3473f882001-02-23 17:55:21 +00003341 * compute depth to root
3342 */
3343 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003344 if (cur->parent == node1)
Owen Taylor3473f882001-02-23 17:55:21 +00003345 return(1);
3346 depth2++;
3347 }
3348 root = cur;
3349 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003350 if (cur->parent == node2)
Owen Taylor3473f882001-02-23 17:55:21 +00003351 return(-1);
3352 depth1++;
3353 }
3354 /*
3355 * Distinct document (or distinct entities :-( ) case.
3356 */
3357 if (root != cur) {
3358 return(-2);
3359 }
3360 /*
3361 * get the nearest common ancestor.
3362 */
3363 while (depth1 > depth2) {
3364 depth1--;
3365 node1 = node1->parent;
3366 }
3367 while (depth2 > depth1) {
3368 depth2--;
3369 node2 = node2->parent;
3370 }
3371 while (node1->parent != node2->parent) {
3372 node1 = node1->parent;
3373 node2 = node2->parent;
3374 /* should not happen but just in case ... */
3375 if ((node1 == NULL) || (node2 == NULL))
3376 return(-2);
3377 }
3378 /*
3379 * Find who's first.
3380 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003381 if (node1 == node2->prev)
3382 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003383 if (node1 == node2->next)
3384 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003385 /*
3386 * Speedup using document order if availble.
3387 */
3388 if ((node1->type == XML_ELEMENT_NODE) &&
3389 (node2->type == XML_ELEMENT_NODE) &&
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003390 (0 > (ptrdiff_t) node1->content) &&
3391 (0 > (ptrdiff_t) node2->content) &&
Daniel Veillardf49be472004-02-17 11:48:18 +00003392 (node1->doc == node2->doc)) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003393 ptrdiff_t l1, l2;
Daniel Veillardf49be472004-02-17 11:48:18 +00003394
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003395 l1 = -((ptrdiff_t) node1->content);
3396 l2 = -((ptrdiff_t) node2->content);
Daniel Veillardf49be472004-02-17 11:48:18 +00003397 if (l1 < l2)
3398 return(1);
3399 if (l1 > l2)
3400 return(-1);
3401 }
3402
Owen Taylor3473f882001-02-23 17:55:21 +00003403 for (cur = node1->next;cur != NULL;cur = cur->next)
3404 if (cur == node2)
3405 return(1);
3406 return(-1); /* assume there is no sibling list corruption */
3407}
3408
3409/**
3410 * xmlXPathNodeSetSort:
3411 * @set: the node set
3412 *
3413 * Sort the node set in document order
3414 */
3415void
3416xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Vojtech Fried3e031b72012-08-24 16:52:44 +08003417#ifndef WITH_TIM_SORT
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003418 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003419 xmlNodePtr tmp;
Vojtech Fried3e031b72012-08-24 16:52:44 +08003420#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003421
3422 if (set == NULL)
3423 return;
3424
Vojtech Fried3e031b72012-08-24 16:52:44 +08003425#ifndef WITH_TIM_SORT
3426 /*
3427 * Use the old Shell's sort implementation to sort the node-set
3428 * Timsort ought to be quite faster
3429 */
Owen Taylor3473f882001-02-23 17:55:21 +00003430 len = set->nodeNr;
3431 for (incr = len / 2; incr > 0; incr /= 2) {
3432 for (i = incr; i < len; i++) {
3433 j = i - incr;
3434 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003435#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003436 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3437 set->nodeTab[j + incr]) == -1)
3438#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003439 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003440 set->nodeTab[j + incr]) == -1)
3441#endif
3442 {
Owen Taylor3473f882001-02-23 17:55:21 +00003443 tmp = set->nodeTab[j];
3444 set->nodeTab[j] = set->nodeTab[j + incr];
3445 set->nodeTab[j + incr] = tmp;
3446 j -= incr;
3447 } else
3448 break;
3449 }
3450 }
3451 }
Vojtech Fried3e031b72012-08-24 16:52:44 +08003452#else /* WITH_TIM_SORT */
3453 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3454#endif /* WITH_TIM_SORT */
Owen Taylor3473f882001-02-23 17:55:21 +00003455}
3456
3457#define XML_NODESET_DEFAULT 10
3458/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003459 * xmlXPathNodeSetDupNs:
3460 * @node: the parent node of the namespace XPath node
3461 * @ns: the libxml namespace declaration node.
3462 *
3463 * Namespace node in libxml don't match the XPath semantic. In a node set
3464 * the namespace nodes are duplicated and the next pointer is set to the
3465 * parent node in the XPath semantic.
3466 *
3467 * Returns the newly created object.
3468 */
3469static xmlNodePtr
3470xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3471 xmlNsPtr cur;
3472
3473 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3474 return(NULL);
3475 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3476 return((xmlNodePtr) ns);
3477
3478 /*
3479 * Allocate a new Namespace and fill the fields.
3480 */
3481 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3482 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003483 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003484 return(NULL);
3485 }
3486 memset(cur, 0, sizeof(xmlNs));
3487 cur->type = XML_NAMESPACE_DECL;
3488 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003489 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003490 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003491 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003492 cur->next = (xmlNsPtr) node;
3493 return((xmlNodePtr) cur);
3494}
3495
3496/**
3497 * xmlXPathNodeSetFreeNs:
3498 * @ns: the XPath namespace node found in a nodeset.
3499 *
William M. Brack08171912003-12-29 02:52:11 +00003500 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003501 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003502 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003503 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003504void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003505xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3506 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3507 return;
3508
3509 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3510 if (ns->href != NULL)
3511 xmlFree((xmlChar *)ns->href);
3512 if (ns->prefix != NULL)
3513 xmlFree((xmlChar *)ns->prefix);
3514 xmlFree(ns);
3515 }
3516}
3517
3518/**
Owen Taylor3473f882001-02-23 17:55:21 +00003519 * xmlXPathNodeSetCreate:
3520 * @val: an initial xmlNodePtr, or NULL
3521 *
3522 * Create a new xmlNodeSetPtr of type double and of value @val
3523 *
3524 * Returns the newly created object.
3525 */
3526xmlNodeSetPtr
3527xmlXPathNodeSetCreate(xmlNodePtr val) {
3528 xmlNodeSetPtr ret;
3529
3530 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3531 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003532 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003533 return(NULL);
3534 }
3535 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3536 if (val != NULL) {
3537 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3538 sizeof(xmlNodePtr));
3539 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003540 xmlXPathErrMemory(NULL, "creating nodeset\n");
3541 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003542 return(NULL);
3543 }
3544 memset(ret->nodeTab, 0 ,
3545 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3546 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003547 if (val->type == XML_NAMESPACE_DECL) {
3548 xmlNsPtr ns = (xmlNsPtr) val;
3549
3550 ret->nodeTab[ret->nodeNr++] =
3551 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3552 } else
3553 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003554 }
3555 return(ret);
3556}
3557
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003558/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003559 * xmlXPathNodeSetCreateSize:
3560 * @size: the initial size of the set
3561 *
3562 * Create a new xmlNodeSetPtr of type double and of value @val
3563 *
3564 * Returns the newly created object.
3565 */
3566static xmlNodeSetPtr
3567xmlXPathNodeSetCreateSize(int size) {
3568 xmlNodeSetPtr ret;
3569
3570 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3571 if (ret == NULL) {
3572 xmlXPathErrMemory(NULL, "creating nodeset\n");
3573 return(NULL);
3574 }
3575 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3576 if (size < XML_NODESET_DEFAULT)
3577 size = XML_NODESET_DEFAULT;
3578 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3579 if (ret->nodeTab == NULL) {
3580 xmlXPathErrMemory(NULL, "creating nodeset\n");
3581 xmlFree(ret);
3582 return(NULL);
3583 }
3584 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003585 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003586 return(ret);
3587}
3588
3589/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003590 * xmlXPathNodeSetContains:
3591 * @cur: the node-set
3592 * @val: the node
3593 *
3594 * checks whether @cur contains @val
3595 *
3596 * Returns true (1) if @cur contains @val, false (0) otherwise
3597 */
3598int
3599xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3600 int i;
3601
Daniel Veillarda82b1822004-11-08 16:24:57 +00003602 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003603 if (val->type == XML_NAMESPACE_DECL) {
3604 for (i = 0; i < cur->nodeNr; i++) {
3605 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3606 xmlNsPtr ns1, ns2;
3607
3608 ns1 = (xmlNsPtr) val;
3609 ns2 = (xmlNsPtr) cur->nodeTab[i];
3610 if (ns1 == ns2)
3611 return(1);
3612 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3613 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3614 return(1);
3615 }
3616 }
3617 } else {
3618 for (i = 0; i < cur->nodeNr; i++) {
3619 if (cur->nodeTab[i] == val)
3620 return(1);
3621 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003622 }
3623 return(0);
3624}
3625
3626/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003627 * xmlXPathNodeSetAddNs:
3628 * @cur: the initial node set
3629 * @node: the hosting node
3630 * @ns: a the namespace node
3631 *
3632 * add a new namespace node to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003633 *
3634 * Returns 0 in case of success and -1 in case of error
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003635 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003636int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003637xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3638 int i;
3639
Daniel Veillard45490ae2008-07-29 09:13:19 +00003640
Daniel Veillarda82b1822004-11-08 16:24:57 +00003641 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3642 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003643 (node->type != XML_ELEMENT_NODE))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003644 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003645
William M. Brack08171912003-12-29 02:52:11 +00003646 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003647 /*
William M. Brack08171912003-12-29 02:52:11 +00003648 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003649 */
3650 for (i = 0;i < cur->nodeNr;i++) {
3651 if ((cur->nodeTab[i] != NULL) &&
3652 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003653 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003654 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003655 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003656 }
3657
3658 /*
3659 * grow the nodeTab if needed
3660 */
3661 if (cur->nodeMax == 0) {
3662 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3663 sizeof(xmlNodePtr));
3664 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003665 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003666 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003667 }
3668 memset(cur->nodeTab, 0 ,
3669 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3670 cur->nodeMax = XML_NODESET_DEFAULT;
3671 } else if (cur->nodeNr == cur->nodeMax) {
3672 xmlNodePtr *temp;
3673
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003674 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3675 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003676 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003677 }
Chris Evansd7958b22011-03-23 08:13:06 +08003678 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003679 sizeof(xmlNodePtr));
3680 if (temp == 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 }
Chris Evansd7958b22011-03-23 08:13:06 +08003684 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003685 cur->nodeTab = temp;
3686 }
3687 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003688 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003689}
3690
3691/**
Owen Taylor3473f882001-02-23 17:55:21 +00003692 * xmlXPathNodeSetAdd:
3693 * @cur: the initial node set
3694 * @val: a new xmlNodePtr
3695 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003696 * add a new xmlNodePtr to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003697 *
3698 * Returns 0 in case of success, and -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00003699 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003700int
Owen Taylor3473f882001-02-23 17:55:21 +00003701xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3702 int i;
3703
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003704 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003705
William M. Brack08171912003-12-29 02:52:11 +00003706 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003707 /*
Shlomi Fishd5bd2a92016-04-03 05:14:44 +03003708 * prevent duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003709 */
3710 for (i = 0;i < cur->nodeNr;i++)
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003711 if (cur->nodeTab[i] == val) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003712
3713 /*
3714 * grow the nodeTab if needed
3715 */
3716 if (cur->nodeMax == 0) {
3717 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3718 sizeof(xmlNodePtr));
3719 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003720 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003721 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003722 }
3723 memset(cur->nodeTab, 0 ,
3724 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3725 cur->nodeMax = XML_NODESET_DEFAULT;
3726 } else if (cur->nodeNr == cur->nodeMax) {
3727 xmlNodePtr *temp;
3728
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003729 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3730 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003731 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003732 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003733 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003734 sizeof(xmlNodePtr));
3735 if (temp == 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 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003739 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003740 cur->nodeTab = temp;
3741 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003742 if (val->type == XML_NAMESPACE_DECL) {
3743 xmlNsPtr ns = (xmlNsPtr) val;
3744
Daniel Veillard45490ae2008-07-29 09:13:19 +00003745 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003746 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3747 } else
3748 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003749 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003750}
3751
3752/**
3753 * xmlXPathNodeSetAddUnique:
3754 * @cur: the initial node set
3755 * @val: a new xmlNodePtr
3756 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003757 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003758 * when we are sure the node is not already in the set.
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003759 *
3760 * Returns 0 in case of success and -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00003761 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003762int
Owen Taylor3473f882001-02-23 17:55:21 +00003763xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003764 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003765
William M. Brack08171912003-12-29 02:52:11 +00003766 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003767 /*
3768 * grow the nodeTab if needed
3769 */
3770 if (cur->nodeMax == 0) {
3771 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3772 sizeof(xmlNodePtr));
3773 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003774 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003775 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003776 }
3777 memset(cur->nodeTab, 0 ,
3778 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3779 cur->nodeMax = XML_NODESET_DEFAULT;
3780 } else if (cur->nodeNr == cur->nodeMax) {
3781 xmlNodePtr *temp;
3782
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003783 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3784 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003785 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003786 }
Chris Evansd7958b22011-03-23 08:13:06 +08003787 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003788 sizeof(xmlNodePtr));
3789 if (temp == 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 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003794 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003795 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003796 if (val->type == XML_NAMESPACE_DECL) {
3797 xmlNsPtr ns = (xmlNsPtr) val;
3798
Daniel Veillard45490ae2008-07-29 09:13:19 +00003799 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003800 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3801 } else
3802 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003803 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003804}
3805
3806/**
3807 * xmlXPathNodeSetMerge:
3808 * @val1: the first NodeSet or NULL
3809 * @val2: the second NodeSet
3810 *
3811 * Merges two nodesets, all nodes from @val2 are added to @val1
3812 * if @val1 is NULL, a new set is created and copied from @val2
3813 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003814 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003815 */
3816xmlNodeSetPtr
3817xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003818 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003819 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003820
3821 if (val2 == NULL) return(val1);
3822 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003823 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003824 if (val1 == NULL)
3825 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003826#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003827 /*
3828 * TODO: The optimization won't work in every case, since
3829 * those nasty namespace nodes need to be added with
3830 * xmlXPathNodeSetDupNs() to the set; thus a pure
3831 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003832 * If there was a flag on the nodesetval, indicating that
3833 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003834 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003835 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003836 * Optimization: Create an equally sized node-set
3837 * and memcpy the content.
3838 */
3839 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3840 if (val1 == NULL)
3841 return(NULL);
3842 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003843 if (val2->nodeNr == 1)
3844 *(val1->nodeTab) = *(val2->nodeTab);
3845 else {
3846 memcpy(val1->nodeTab, val2->nodeTab,
3847 val2->nodeNr * sizeof(xmlNodePtr));
3848 }
3849 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003850 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003851 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003852#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003853 }
3854
William M. Brack08171912003-12-29 02:52:11 +00003855 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003856 initNr = val1->nodeNr;
3857
3858 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003859 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003860 /*
William M. Brack08171912003-12-29 02:52:11 +00003861 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003862 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003863 skip = 0;
3864 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003865 n1 = val1->nodeTab[j];
3866 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003867 skip = 1;
3868 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003869 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003870 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003871 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3872 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3873 ((xmlNsPtr) n2)->prefix)))
3874 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003875 skip = 1;
3876 break;
3877 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003878 }
3879 }
3880 if (skip)
3881 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003882
3883 /*
3884 * grow the nodeTab if needed
3885 */
3886 if (val1->nodeMax == 0) {
3887 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3888 sizeof(xmlNodePtr));
3889 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003890 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003891 return(NULL);
3892 }
3893 memset(val1->nodeTab, 0 ,
3894 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3895 val1->nodeMax = XML_NODESET_DEFAULT;
3896 } else if (val1->nodeNr == val1->nodeMax) {
3897 xmlNodePtr *temp;
3898
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003899 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3900 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3901 return(NULL);
3902 }
Chris Evansd7958b22011-03-23 08:13:06 +08003903 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003904 sizeof(xmlNodePtr));
3905 if (temp == 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 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003910 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003911 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003912 if (n2->type == XML_NAMESPACE_DECL) {
3913 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003914
3915 val1->nodeTab[val1->nodeNr++] =
3916 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3917 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003918 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003919 }
3920
3921 return(val1);
3922}
3923
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003924
3925/**
3926 * xmlXPathNodeSetMergeAndClear:
3927 * @set1: the first NodeSet or NULL
3928 * @set2: the second NodeSet
3929 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3930 *
3931 * Merges two nodesets, all nodes from @set2 are added to @set1
3932 * if @set1 is NULL, a new set is created and copied from @set2.
3933 * Checks for duplicate nodes. Clears set2.
3934 *
3935 * Returns @set1 once extended or NULL in case of error.
3936 */
3937static xmlNodeSetPtr
3938xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3939 int hasNullEntries)
3940{
3941 if ((set1 == NULL) && (hasNullEntries == 0)) {
3942 /*
3943 * Note that doing a memcpy of the list, namespace nodes are
3944 * just assigned to set1, since set2 is cleared anyway.
3945 */
3946 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3947 if (set1 == NULL)
3948 return(NULL);
3949 if (set2->nodeNr != 0) {
3950 memcpy(set1->nodeTab, set2->nodeTab,
3951 set2->nodeNr * sizeof(xmlNodePtr));
3952 set1->nodeNr = set2->nodeNr;
3953 }
3954 } else {
3955 int i, j, initNbSet1;
3956 xmlNodePtr n1, n2;
3957
3958 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003959 set1 = xmlXPathNodeSetCreate(NULL);
3960 if (set1 == NULL)
3961 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003962
Daniel Veillard45490ae2008-07-29 09:13:19 +00003963 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003964 for (i = 0;i < set2->nodeNr;i++) {
3965 n2 = set2->nodeTab[i];
3966 /*
3967 * Skip NULLed entries.
3968 */
3969 if (n2 == NULL)
3970 continue;
3971 /*
3972 * Skip duplicates.
3973 */
3974 for (j = 0; j < initNbSet1; j++) {
3975 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003976 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003977 goto skip_node;
3978 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3979 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003980 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003981 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3982 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3983 ((xmlNsPtr) n2)->prefix)))
3984 {
3985 /*
3986 * Free the namespace node.
3987 */
3988 set2->nodeTab[i] = NULL;
3989 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3990 goto skip_node;
3991 }
3992 }
3993 }
3994 /*
3995 * grow the nodeTab if needed
3996 */
3997 if (set1->nodeMax == 0) {
3998 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3999 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4000 if (set1->nodeTab == NULL) {
4001 xmlXPathErrMemory(NULL, "merging nodeset\n");
4002 return(NULL);
4003 }
4004 memset(set1->nodeTab, 0,
4005 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4006 set1->nodeMax = XML_NODESET_DEFAULT;
4007 } else if (set1->nodeNr >= set1->nodeMax) {
4008 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004009
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004010 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4011 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4012 return(NULL);
4013 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004014 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004015 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004016 if (temp == NULL) {
4017 xmlXPathErrMemory(NULL, "merging nodeset\n");
4018 return(NULL);
4019 }
4020 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004021 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004022 }
Nick Wellnhofer9d08b342017-05-21 16:46:12 +02004023 set1->nodeTab[set1->nodeNr++] = n2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004024skip_node:
4025 {}
4026 }
4027 }
4028 set2->nodeNr = 0;
4029 return(set1);
4030}
4031
4032/**
4033 * xmlXPathNodeSetMergeAndClearNoDupls:
4034 * @set1: the first NodeSet or NULL
4035 * @set2: the second NodeSet
4036 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4037 *
4038 * Merges two nodesets, all nodes from @set2 are added to @set1
4039 * if @set1 is NULL, a new set is created and copied from @set2.
4040 * Doesn't chack for duplicate nodes. Clears set2.
4041 *
4042 * Returns @set1 once extended or NULL in case of error.
4043 */
4044static xmlNodeSetPtr
4045xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4046 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004047{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004048 if (set2 == NULL)
4049 return(set1);
4050 if ((set1 == NULL) && (hasNullEntries == 0)) {
4051 /*
4052 * Note that doing a memcpy of the list, namespace nodes are
4053 * just assigned to set1, since set2 is cleared anyway.
4054 */
4055 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4056 if (set1 == NULL)
4057 return(NULL);
4058 if (set2->nodeNr != 0) {
4059 memcpy(set1->nodeTab, set2->nodeTab,
4060 set2->nodeNr * sizeof(xmlNodePtr));
4061 set1->nodeNr = set2->nodeNr;
4062 }
4063 } else {
4064 int i;
4065 xmlNodePtr n2;
4066
4067 if (set1 == NULL)
4068 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004069 if (set1 == NULL)
4070 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004071
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004072 for (i = 0;i < set2->nodeNr;i++) {
4073 n2 = set2->nodeTab[i];
4074 /*
4075 * Skip NULLed entries.
4076 */
4077 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004078 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004079 if (set1->nodeMax == 0) {
4080 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4081 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4082 if (set1->nodeTab == NULL) {
4083 xmlXPathErrMemory(NULL, "merging nodeset\n");
4084 return(NULL);
4085 }
4086 memset(set1->nodeTab, 0,
4087 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4088 set1->nodeMax = XML_NODESET_DEFAULT;
4089 } else if (set1->nodeNr >= set1->nodeMax) {
4090 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004091
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004092 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4093 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4094 return(NULL);
4095 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004096 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004097 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004098 if (temp == NULL) {
4099 xmlXPathErrMemory(NULL, "merging nodeset\n");
4100 return(NULL);
4101 }
4102 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004103 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004104 }
4105 set1->nodeTab[set1->nodeNr++] = n2;
4106 }
4107 }
4108 set2->nodeNr = 0;
4109 return(set1);
4110}
Daniel Veillard75be0132002-03-13 10:03:35 +00004111
4112/**
Owen Taylor3473f882001-02-23 17:55:21 +00004113 * xmlXPathNodeSetDel:
4114 * @cur: the initial node set
4115 * @val: an xmlNodePtr
4116 *
4117 * Removes an xmlNodePtr from an existing NodeSet
4118 */
4119void
4120xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4121 int i;
4122
4123 if (cur == NULL) return;
4124 if (val == NULL) return;
4125
4126 /*
William M. Brack08171912003-12-29 02:52:11 +00004127 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004128 */
4129 for (i = 0;i < cur->nodeNr;i++)
4130 if (cur->nodeTab[i] == val) break;
4131
William M. Brack08171912003-12-29 02:52:11 +00004132 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004133#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004134 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004135 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4136 val->name);
4137#endif
4138 return;
4139 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004140 if ((cur->nodeTab[i] != NULL) &&
4141 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4142 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004143 cur->nodeNr--;
4144 for (;i < cur->nodeNr;i++)
4145 cur->nodeTab[i] = cur->nodeTab[i + 1];
4146 cur->nodeTab[cur->nodeNr] = NULL;
4147}
4148
4149/**
4150 * xmlXPathNodeSetRemove:
4151 * @cur: the initial node set
4152 * @val: the index to remove
4153 *
4154 * Removes an entry from an existing NodeSet list.
4155 */
4156void
4157xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4158 if (cur == NULL) return;
4159 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004160 if ((cur->nodeTab[val] != NULL) &&
4161 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4162 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004163 cur->nodeNr--;
4164 for (;val < cur->nodeNr;val++)
4165 cur->nodeTab[val] = cur->nodeTab[val + 1];
4166 cur->nodeTab[cur->nodeNr] = NULL;
4167}
4168
4169/**
4170 * xmlXPathFreeNodeSet:
4171 * @obj: the xmlNodeSetPtr to free
4172 *
4173 * Free the NodeSet compound (not the actual nodes !).
4174 */
4175void
4176xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4177 if (obj == NULL) return;
4178 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004179 int i;
4180
William M. Brack08171912003-12-29 02:52:11 +00004181 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004182 for (i = 0;i < obj->nodeNr;i++)
4183 if ((obj->nodeTab[i] != NULL) &&
4184 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4185 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004186 xmlFree(obj->nodeTab);
4187 }
Owen Taylor3473f882001-02-23 17:55:21 +00004188 xmlFree(obj);
4189}
4190
4191/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004192 * xmlXPathNodeSetClearFromPos:
4193 * @set: the node set to be cleared
4194 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004195 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004196 * Clears the list from temporary XPath objects (e.g. namespace nodes
4197 * are feed) starting with the entry at @pos, but does *not* free the list
4198 * itself. Sets the length of the list to @pos.
4199 */
4200static void
4201xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4202{
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004203 if ((set == NULL) || (pos >= set->nodeNr))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004204 return;
4205 else if ((hasNsNodes)) {
4206 int i;
4207 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004208
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004209 for (i = pos; i < set->nodeNr; i++) {
4210 node = set->nodeTab[i];
4211 if ((node != NULL) &&
4212 (node->type == XML_NAMESPACE_DECL))
4213 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004214 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004215 }
4216 set->nodeNr = pos;
4217}
4218
4219/**
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004220 * xmlXPathNodeSetClear:
4221 * @set: the node set to clear
4222 *
4223 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4224 * are feed), but does *not* free the list itself. Sets the length of the
4225 * list to 0.
4226 */
4227static void
4228xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4229{
4230 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4231}
4232
4233/**
4234 * xmlXPathNodeSetKeepLast:
4235 * @set: the node set to be cleared
4236 *
4237 * Move the last node to the first position and clear temporary XPath objects
4238 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4239 * to 1.
4240 */
4241static void
4242xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4243{
4244 int i;
4245 xmlNodePtr node;
4246
4247 if ((set == NULL) || (set->nodeNr <= 1))
4248 return;
4249 for (i = 0; i < set->nodeNr - 1; i++) {
4250 node = set->nodeTab[i];
4251 if ((node != NULL) &&
4252 (node->type == XML_NAMESPACE_DECL))
4253 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4254 }
4255 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4256 set->nodeNr = 1;
4257}
4258
4259/**
Owen Taylor3473f882001-02-23 17:55:21 +00004260 * xmlXPathFreeValueTree:
4261 * @obj: the xmlNodeSetPtr to free
4262 *
4263 * Free the NodeSet compound and the actual tree, this is different
4264 * from xmlXPathFreeNodeSet()
4265 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004266static void
Owen Taylor3473f882001-02-23 17:55:21 +00004267xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4268 int i;
4269
4270 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004271
4272 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004273 for (i = 0;i < obj->nodeNr;i++) {
4274 if (obj->nodeTab[i] != NULL) {
4275 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4276 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4277 } else {
4278 xmlFreeNodeList(obj->nodeTab[i]);
4279 }
4280 }
4281 }
Owen Taylor3473f882001-02-23 17:55:21 +00004282 xmlFree(obj->nodeTab);
4283 }
Owen Taylor3473f882001-02-23 17:55:21 +00004284 xmlFree(obj);
4285}
4286
4287#if defined(DEBUG) || defined(DEBUG_STEP)
4288/**
4289 * xmlGenericErrorContextNodeSet:
4290 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004291 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004292 *
4293 * Quick display of a NodeSet
4294 */
4295void
4296xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4297 int i;
4298
4299 if (output == NULL) output = xmlGenericErrorContext;
4300 if (obj == NULL) {
4301 fprintf(output, "NodeSet == NULL !\n");
4302 return;
4303 }
4304 if (obj->nodeNr == 0) {
4305 fprintf(output, "NodeSet is empty\n");
4306 return;
4307 }
4308 if (obj->nodeTab == NULL) {
4309 fprintf(output, " nodeTab == NULL !\n");
4310 return;
4311 }
4312 for (i = 0; i < obj->nodeNr; i++) {
4313 if (obj->nodeTab[i] == NULL) {
4314 fprintf(output, " NULL !\n");
4315 return;
4316 }
4317 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4318 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4319 fprintf(output, " /");
4320 else if (obj->nodeTab[i]->name == NULL)
4321 fprintf(output, " noname!");
4322 else fprintf(output, " %s", obj->nodeTab[i]->name);
4323 }
4324 fprintf(output, "\n");
4325}
4326#endif
4327
4328/**
4329 * xmlXPathNewNodeSet:
4330 * @val: the NodePtr value
4331 *
4332 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4333 * it with the single Node @val
4334 *
4335 * Returns the newly created object.
4336 */
4337xmlXPathObjectPtr
4338xmlXPathNewNodeSet(xmlNodePtr val) {
4339 xmlXPathObjectPtr ret;
4340
4341 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4342 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004343 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004344 return(NULL);
4345 }
4346 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4347 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004348 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004349 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004350 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004351#ifdef XP_DEBUG_OBJ_USAGE
4352 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4353#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004354 return(ret);
4355}
4356
4357/**
4358 * xmlXPathNewValueTree:
4359 * @val: the NodePtr value
4360 *
4361 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4362 * it with the tree root @val
4363 *
4364 * Returns the newly created object.
4365 */
4366xmlXPathObjectPtr
4367xmlXPathNewValueTree(xmlNodePtr val) {
4368 xmlXPathObjectPtr ret;
4369
4370 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4371 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004372 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004373 return(NULL);
4374 }
4375 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4376 ret->type = XPATH_XSLT_TREE;
Elliott Hughes7fbecab2019-01-10 16:42:03 -08004377 ret->boolval = 1;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004378 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004379 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004380#ifdef XP_DEBUG_OBJ_USAGE
4381 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4382#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004383 return(ret);
4384}
4385
4386/**
4387 * xmlXPathNewNodeSetList:
4388 * @val: an existing NodeSet
4389 *
4390 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4391 * it with the Nodeset @val
4392 *
4393 * Returns the newly created object.
4394 */
4395xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004396xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4397{
Owen Taylor3473f882001-02-23 17:55:21 +00004398 xmlXPathObjectPtr ret;
4399 int i;
4400
4401 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004402 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004403 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004404 ret = xmlXPathNewNodeSet(NULL);
4405 else {
4406 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004407 if (ret) {
4408 for (i = 1; i < val->nodeNr; ++i) {
4409 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4410 < 0) break;
4411 }
4412 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004413 }
Owen Taylor3473f882001-02-23 17:55:21 +00004414
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004415 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004416}
4417
4418/**
4419 * xmlXPathWrapNodeSet:
4420 * @val: the NodePtr value
4421 *
4422 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4423 *
4424 * Returns the newly created object.
4425 */
4426xmlXPathObjectPtr
4427xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4428 xmlXPathObjectPtr ret;
4429
4430 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4431 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004432 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004433 return(NULL);
4434 }
4435 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4436 ret->type = XPATH_NODESET;
4437 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004438#ifdef XP_DEBUG_OBJ_USAGE
4439 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4440#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004441 return(ret);
4442}
4443
4444/**
4445 * xmlXPathFreeNodeSetList:
4446 * @obj: an existing NodeSetList object
4447 *
4448 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4449 * the list contrary to xmlXPathFreeObject().
4450 */
4451void
4452xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4453 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004454#ifdef XP_DEBUG_OBJ_USAGE
4455 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4456#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004457 xmlFree(obj);
4458}
4459
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004460/**
4461 * xmlXPathDifference:
4462 * @nodes1: a node-set
4463 * @nodes2: a node-set
4464 *
4465 * Implements the EXSLT - Sets difference() function:
4466 * node-set set:difference (node-set, node-set)
4467 *
4468 * Returns the difference between the two node sets, or nodes1 if
4469 * nodes2 is empty
4470 */
4471xmlNodeSetPtr
4472xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4473 xmlNodeSetPtr ret;
4474 int i, l1;
4475 xmlNodePtr cur;
4476
4477 if (xmlXPathNodeSetIsEmpty(nodes2))
4478 return(nodes1);
4479
4480 ret = xmlXPathNodeSetCreate(NULL);
4481 if (xmlXPathNodeSetIsEmpty(nodes1))
4482 return(ret);
4483
4484 l1 = xmlXPathNodeSetGetLength(nodes1);
4485
4486 for (i = 0; i < l1; i++) {
4487 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004488 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4489 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4490 break;
4491 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004492 }
4493 return(ret);
4494}
4495
4496/**
4497 * xmlXPathIntersection:
4498 * @nodes1: a node-set
4499 * @nodes2: a node-set
4500 *
4501 * Implements the EXSLT - Sets intersection() function:
4502 * node-set set:intersection (node-set, node-set)
4503 *
4504 * Returns a node set comprising the nodes that are within both the
4505 * node sets passed as arguments
4506 */
4507xmlNodeSetPtr
4508xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4509 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4510 int i, l1;
4511 xmlNodePtr cur;
4512
Daniel Veillardf88d8492008-04-01 08:00:31 +00004513 if (ret == NULL)
4514 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004515 if (xmlXPathNodeSetIsEmpty(nodes1))
4516 return(ret);
4517 if (xmlXPathNodeSetIsEmpty(nodes2))
4518 return(ret);
4519
4520 l1 = xmlXPathNodeSetGetLength(nodes1);
4521
4522 for (i = 0; i < l1; i++) {
4523 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004524 if (xmlXPathNodeSetContains(nodes2, cur)) {
4525 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4526 break;
4527 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004528 }
4529 return(ret);
4530}
4531
4532/**
4533 * xmlXPathDistinctSorted:
4534 * @nodes: a node-set, sorted by document order
4535 *
4536 * Implements the EXSLT - Sets distinct() function:
4537 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004538 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004539 * Returns a subset of the nodes contained in @nodes, or @nodes if
4540 * it is empty
4541 */
4542xmlNodeSetPtr
4543xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4544 xmlNodeSetPtr ret;
4545 xmlHashTablePtr hash;
4546 int i, l;
4547 xmlChar * strval;
4548 xmlNodePtr cur;
4549
4550 if (xmlXPathNodeSetIsEmpty(nodes))
4551 return(nodes);
4552
4553 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004554 if (ret == NULL)
4555 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004556 l = xmlXPathNodeSetGetLength(nodes);
4557 hash = xmlHashCreate (l);
4558 for (i = 0; i < l; i++) {
4559 cur = xmlXPathNodeSetItem(nodes, i);
4560 strval = xmlXPathCastNodeToString(cur);
4561 if (xmlHashLookup(hash, strval) == NULL) {
4562 xmlHashAddEntry(hash, strval, strval);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004563 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4564 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004565 } else {
4566 xmlFree(strval);
4567 }
4568 }
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01004569 xmlHashFree(hash, xmlHashDefaultDeallocator);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004570 return(ret);
4571}
4572
4573/**
4574 * xmlXPathDistinct:
4575 * @nodes: a node-set
4576 *
4577 * Implements the EXSLT - Sets distinct() function:
4578 * node-set set:distinct (node-set)
4579 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4580 * is called with the sorted node-set
4581 *
4582 * Returns a subset of the nodes contained in @nodes, or @nodes if
4583 * it is empty
4584 */
4585xmlNodeSetPtr
4586xmlXPathDistinct (xmlNodeSetPtr nodes) {
4587 if (xmlXPathNodeSetIsEmpty(nodes))
4588 return(nodes);
4589
4590 xmlXPathNodeSetSort(nodes);
4591 return(xmlXPathDistinctSorted(nodes));
4592}
4593
4594/**
4595 * xmlXPathHasSameNodes:
4596 * @nodes1: a node-set
4597 * @nodes2: a node-set
4598 *
4599 * Implements the EXSLT - Sets has-same-nodes function:
4600 * boolean set:has-same-node(node-set, node-set)
4601 *
4602 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4603 * otherwise
4604 */
4605int
4606xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4607 int i, l;
4608 xmlNodePtr cur;
4609
4610 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4611 xmlXPathNodeSetIsEmpty(nodes2))
4612 return(0);
4613
4614 l = xmlXPathNodeSetGetLength(nodes1);
4615 for (i = 0; i < l; i++) {
4616 cur = xmlXPathNodeSetItem(nodes1, i);
4617 if (xmlXPathNodeSetContains(nodes2, cur))
4618 return(1);
4619 }
4620 return(0);
4621}
4622
4623/**
4624 * xmlXPathNodeLeadingSorted:
4625 * @nodes: a node-set, sorted by document order
4626 * @node: a node
4627 *
4628 * Implements the EXSLT - Sets leading() function:
4629 * node-set set:leading (node-set, node-set)
4630 *
4631 * Returns the nodes in @nodes that precede @node in document order,
4632 * @nodes if @node is NULL or an empty node-set if @nodes
4633 * doesn't contain @node
4634 */
4635xmlNodeSetPtr
4636xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4637 int i, l;
4638 xmlNodePtr cur;
4639 xmlNodeSetPtr ret;
4640
4641 if (node == NULL)
4642 return(nodes);
4643
4644 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004645 if (ret == NULL)
4646 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004647 if (xmlXPathNodeSetIsEmpty(nodes) ||
4648 (!xmlXPathNodeSetContains(nodes, node)))
4649 return(ret);
4650
4651 l = xmlXPathNodeSetGetLength(nodes);
4652 for (i = 0; i < l; i++) {
4653 cur = xmlXPathNodeSetItem(nodes, i);
4654 if (cur == node)
4655 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004656 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4657 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004658 }
4659 return(ret);
4660}
4661
4662/**
4663 * xmlXPathNodeLeading:
4664 * @nodes: a node-set
4665 * @node: a node
4666 *
4667 * Implements the EXSLT - Sets leading() function:
4668 * node-set set:leading (node-set, node-set)
4669 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4670 * is called.
4671 *
4672 * Returns the nodes in @nodes that precede @node in document order,
4673 * @nodes if @node is NULL or an empty node-set if @nodes
4674 * doesn't contain @node
4675 */
4676xmlNodeSetPtr
4677xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4678 xmlXPathNodeSetSort(nodes);
4679 return(xmlXPathNodeLeadingSorted(nodes, node));
4680}
4681
4682/**
4683 * xmlXPathLeadingSorted:
4684 * @nodes1: a node-set, sorted by document order
4685 * @nodes2: a node-set, sorted by document order
4686 *
4687 * Implements the EXSLT - Sets leading() function:
4688 * node-set set:leading (node-set, node-set)
4689 *
4690 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4691 * in document order, @nodes1 if @nodes2 is NULL or empty or
4692 * an empty node-set if @nodes1 doesn't contain @nodes2
4693 */
4694xmlNodeSetPtr
4695xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4696 if (xmlXPathNodeSetIsEmpty(nodes2))
4697 return(nodes1);
4698 return(xmlXPathNodeLeadingSorted(nodes1,
4699 xmlXPathNodeSetItem(nodes2, 1)));
4700}
4701
4702/**
4703 * xmlXPathLeading:
4704 * @nodes1: a node-set
4705 * @nodes2: a node-set
4706 *
4707 * Implements the EXSLT - Sets leading() function:
4708 * node-set set:leading (node-set, node-set)
4709 * @nodes1 and @nodes2 are sorted by document order, then
4710 * #exslSetsLeadingSorted is called.
4711 *
4712 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4713 * in document order, @nodes1 if @nodes2 is NULL or empty or
4714 * an empty node-set if @nodes1 doesn't contain @nodes2
4715 */
4716xmlNodeSetPtr
4717xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4718 if (xmlXPathNodeSetIsEmpty(nodes2))
4719 return(nodes1);
4720 if (xmlXPathNodeSetIsEmpty(nodes1))
4721 return(xmlXPathNodeSetCreate(NULL));
4722 xmlXPathNodeSetSort(nodes1);
4723 xmlXPathNodeSetSort(nodes2);
4724 return(xmlXPathNodeLeadingSorted(nodes1,
4725 xmlXPathNodeSetItem(nodes2, 1)));
4726}
4727
4728/**
4729 * xmlXPathNodeTrailingSorted:
4730 * @nodes: a node-set, sorted by document order
4731 * @node: a node
4732 *
4733 * Implements the EXSLT - Sets trailing() function:
4734 * node-set set:trailing (node-set, node-set)
4735 *
4736 * Returns the nodes in @nodes that follow @node in document order,
4737 * @nodes if @node is NULL or an empty node-set if @nodes
4738 * doesn't contain @node
4739 */
4740xmlNodeSetPtr
4741xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4742 int i, l;
4743 xmlNodePtr cur;
4744 xmlNodeSetPtr ret;
4745
4746 if (node == NULL)
4747 return(nodes);
4748
4749 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004750 if (ret == NULL)
4751 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004752 if (xmlXPathNodeSetIsEmpty(nodes) ||
4753 (!xmlXPathNodeSetContains(nodes, node)))
4754 return(ret);
4755
4756 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004757 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004758 cur = xmlXPathNodeSetItem(nodes, i);
4759 if (cur == node)
4760 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004761 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4762 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004763 }
William M. Brack97ac8192007-06-06 17:19:24 +00004764 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004765 return(ret);
4766}
4767
4768/**
4769 * xmlXPathNodeTrailing:
4770 * @nodes: a node-set
4771 * @node: a node
4772 *
4773 * Implements the EXSLT - Sets trailing() function:
4774 * node-set set:trailing (node-set, node-set)
4775 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4776 * is called.
4777 *
4778 * Returns the nodes in @nodes that follow @node in document order,
4779 * @nodes if @node is NULL or an empty node-set if @nodes
4780 * doesn't contain @node
4781 */
4782xmlNodeSetPtr
4783xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4784 xmlXPathNodeSetSort(nodes);
4785 return(xmlXPathNodeTrailingSorted(nodes, node));
4786}
4787
4788/**
4789 * xmlXPathTrailingSorted:
4790 * @nodes1: a node-set, sorted by document order
4791 * @nodes2: a node-set, sorted by document order
4792 *
4793 * Implements the EXSLT - Sets trailing() function:
4794 * node-set set:trailing (node-set, node-set)
4795 *
4796 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4797 * in document order, @nodes1 if @nodes2 is NULL or empty or
4798 * an empty node-set if @nodes1 doesn't contain @nodes2
4799 */
4800xmlNodeSetPtr
4801xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4802 if (xmlXPathNodeSetIsEmpty(nodes2))
4803 return(nodes1);
4804 return(xmlXPathNodeTrailingSorted(nodes1,
4805 xmlXPathNodeSetItem(nodes2, 0)));
4806}
4807
4808/**
4809 * xmlXPathTrailing:
4810 * @nodes1: a node-set
4811 * @nodes2: a node-set
4812 *
4813 * Implements the EXSLT - Sets trailing() function:
4814 * node-set set:trailing (node-set, node-set)
4815 * @nodes1 and @nodes2 are sorted by document order, then
4816 * #xmlXPathTrailingSorted is called.
4817 *
4818 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4819 * in document order, @nodes1 if @nodes2 is NULL or empty or
4820 * an empty node-set if @nodes1 doesn't contain @nodes2
4821 */
4822xmlNodeSetPtr
4823xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4824 if (xmlXPathNodeSetIsEmpty(nodes2))
4825 return(nodes1);
4826 if (xmlXPathNodeSetIsEmpty(nodes1))
4827 return(xmlXPathNodeSetCreate(NULL));
4828 xmlXPathNodeSetSort(nodes1);
4829 xmlXPathNodeSetSort(nodes2);
4830 return(xmlXPathNodeTrailingSorted(nodes1,
4831 xmlXPathNodeSetItem(nodes2, 0)));
4832}
4833
Owen Taylor3473f882001-02-23 17:55:21 +00004834/************************************************************************
4835 * *
4836 * Routines to handle extra functions *
4837 * *
4838 ************************************************************************/
4839
4840/**
4841 * xmlXPathRegisterFunc:
4842 * @ctxt: the XPath context
4843 * @name: the function name
4844 * @f: the function implementation or NULL
4845 *
4846 * Register a new function. If @f is NULL it unregisters the function
4847 *
4848 * Returns 0 in case of success, -1 in case of error
4849 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004850int
Owen Taylor3473f882001-02-23 17:55:21 +00004851xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4852 xmlXPathFunction f) {
4853 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4854}
4855
4856/**
4857 * xmlXPathRegisterFuncNS:
4858 * @ctxt: the XPath context
4859 * @name: the function name
4860 * @ns_uri: the function namespace URI
4861 * @f: the function implementation or NULL
4862 *
4863 * Register a new function. If @f is NULL it unregisters the function
4864 *
4865 * Returns 0 in case of success, -1 in case of error
4866 */
4867int
4868xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4869 const xmlChar *ns_uri, xmlXPathFunction f) {
4870 if (ctxt == NULL)
4871 return(-1);
4872 if (name == NULL)
4873 return(-1);
4874
4875 if (ctxt->funcHash == NULL)
4876 ctxt->funcHash = xmlHashCreate(0);
4877 if (ctxt->funcHash == NULL)
4878 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004879 if (f == NULL)
4880 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Nick Wellnhofer13acadb2017-11-12 17:28:12 +01004881XML_IGNORE_PEDANTIC_WARNINGS
4882 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4883XML_POP_WARNINGS
Owen Taylor3473f882001-02-23 17:55:21 +00004884}
4885
4886/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004887 * xmlXPathRegisterFuncLookup:
4888 * @ctxt: the XPath context
4889 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004890 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004891 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004892 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004893 */
4894void
4895xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4896 xmlXPathFuncLookupFunc f,
4897 void *funcCtxt) {
4898 if (ctxt == NULL)
4899 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004900 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004901 ctxt->funcLookupData = funcCtxt;
4902}
4903
4904/**
Owen Taylor3473f882001-02-23 17:55:21 +00004905 * xmlXPathFunctionLookup:
4906 * @ctxt: the XPath context
4907 * @name: the function name
4908 *
4909 * Search in the Function array of the context for the given
4910 * function.
4911 *
4912 * Returns the xmlXPathFunction or NULL if not found
4913 */
4914xmlXPathFunction
4915xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004916 if (ctxt == NULL)
4917 return (NULL);
4918
4919 if (ctxt->funcLookupFunc != NULL) {
4920 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004921 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004922
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004923 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004924 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004925 if (ret != NULL)
4926 return(ret);
4927 }
Owen Taylor3473f882001-02-23 17:55:21 +00004928 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4929}
4930
4931/**
4932 * xmlXPathFunctionLookupNS:
4933 * @ctxt: the XPath context
4934 * @name: the function name
4935 * @ns_uri: the function namespace URI
4936 *
4937 * Search in the Function array of the context for the given
4938 * function.
4939 *
4940 * Returns the xmlXPathFunction or NULL if not found
4941 */
4942xmlXPathFunction
4943xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4944 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004945 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004946
Owen Taylor3473f882001-02-23 17:55:21 +00004947 if (ctxt == NULL)
4948 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004949 if (name == NULL)
4950 return(NULL);
4951
Thomas Broyerba4ad322001-07-26 16:55:21 +00004952 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004953 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004954
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004955 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004956 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004957 if (ret != NULL)
4958 return(ret);
4959 }
4960
4961 if (ctxt->funcHash == NULL)
4962 return(NULL);
4963
Nick Wellnhofer13acadb2017-11-12 17:28:12 +01004964XML_IGNORE_PEDANTIC_WARNINGS
4965 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4966XML_POP_WARNINGS
William M. Brackad0e67c2004-12-01 14:35:10 +00004967 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004968}
4969
4970/**
4971 * xmlXPathRegisteredFuncsCleanup:
4972 * @ctxt: the XPath context
4973 *
4974 * Cleanup the XPath context data associated to registered functions
4975 */
4976void
4977xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4978 if (ctxt == NULL)
4979 return;
4980
4981 xmlHashFree(ctxt->funcHash, NULL);
4982 ctxt->funcHash = NULL;
4983}
4984
4985/************************************************************************
4986 * *
William M. Brack08171912003-12-29 02:52:11 +00004987 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004988 * *
4989 ************************************************************************/
4990
4991/**
4992 * xmlXPathRegisterVariable:
4993 * @ctxt: the XPath context
4994 * @name: the variable name
4995 * @value: the variable value or NULL
4996 *
4997 * Register a new variable value. If @value is NULL it unregisters
4998 * the variable
4999 *
5000 * Returns 0 in case of success, -1 in case of error
5001 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00005002int
Owen Taylor3473f882001-02-23 17:55:21 +00005003xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5004 xmlXPathObjectPtr value) {
5005 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5006}
5007
5008/**
5009 * xmlXPathRegisterVariableNS:
5010 * @ctxt: the XPath context
5011 * @name: the variable name
5012 * @ns_uri: the variable namespace URI
5013 * @value: the variable value or NULL
5014 *
5015 * Register a new variable value. If @value is NULL it unregisters
5016 * the variable
5017 *
5018 * Returns 0 in case of success, -1 in case of error
5019 */
5020int
5021xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5022 const xmlChar *ns_uri,
5023 xmlXPathObjectPtr value) {
5024 if (ctxt == NULL)
5025 return(-1);
5026 if (name == NULL)
5027 return(-1);
5028
5029 if (ctxt->varHash == NULL)
5030 ctxt->varHash = xmlHashCreate(0);
5031 if (ctxt->varHash == NULL)
5032 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00005033 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005034 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005035 xmlXPathFreeObjectEntry));
Owen Taylor3473f882001-02-23 17:55:21 +00005036 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005037 (void *) value, xmlXPathFreeObjectEntry));
Owen Taylor3473f882001-02-23 17:55:21 +00005038}
5039
5040/**
5041 * xmlXPathRegisterVariableLookup:
5042 * @ctxt: the XPath context
5043 * @f: the lookup function
5044 * @data: the lookup data
5045 *
5046 * register an external mechanism to do variable lookup
5047 */
5048void
5049xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5050 xmlXPathVariableLookupFunc f, void *data) {
5051 if (ctxt == NULL)
5052 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00005053 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00005054 ctxt->varLookupData = data;
5055}
5056
5057/**
5058 * xmlXPathVariableLookup:
5059 * @ctxt: the XPath context
5060 * @name: the variable name
5061 *
5062 * Search in the Variable array of the context for the given
5063 * variable value.
5064 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005065 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005066 */
5067xmlXPathObjectPtr
5068xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5069 if (ctxt == NULL)
5070 return(NULL);
5071
5072 if (ctxt->varLookupFunc != NULL) {
5073 xmlXPathObjectPtr ret;
5074
5075 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5076 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00005077 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005078 }
5079 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5080}
5081
5082/**
5083 * xmlXPathVariableLookupNS:
5084 * @ctxt: the XPath context
5085 * @name: the variable name
5086 * @ns_uri: the variable namespace URI
5087 *
5088 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005089 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005090 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005091 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005092 */
5093xmlXPathObjectPtr
5094xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5095 const xmlChar *ns_uri) {
5096 if (ctxt == NULL)
5097 return(NULL);
5098
5099 if (ctxt->varLookupFunc != NULL) {
5100 xmlXPathObjectPtr ret;
5101
5102 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5103 (ctxt->varLookupData, name, ns_uri);
5104 if (ret != NULL) return(ret);
5105 }
5106
5107 if (ctxt->varHash == NULL)
5108 return(NULL);
5109 if (name == NULL)
5110 return(NULL);
5111
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005112 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005113 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005114}
5115
5116/**
5117 * xmlXPathRegisteredVariablesCleanup:
5118 * @ctxt: the XPath context
5119 *
5120 * Cleanup the XPath context data associated to registered variables
5121 */
5122void
5123xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5124 if (ctxt == NULL)
5125 return;
5126
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005127 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
Owen Taylor3473f882001-02-23 17:55:21 +00005128 ctxt->varHash = NULL;
5129}
5130
5131/**
5132 * xmlXPathRegisterNs:
5133 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005134 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005135 * @ns_uri: the namespace name
5136 *
5137 * Register a new namespace. If @ns_uri is NULL it unregisters
5138 * the namespace
5139 *
5140 * Returns 0 in case of success, -1 in case of error
5141 */
5142int
5143xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5144 const xmlChar *ns_uri) {
5145 if (ctxt == NULL)
5146 return(-1);
5147 if (prefix == NULL)
5148 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005149 if (prefix[0] == 0)
5150 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005151
5152 if (ctxt->nsHash == NULL)
5153 ctxt->nsHash = xmlHashCreate(10);
5154 if (ctxt->nsHash == NULL)
5155 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005156 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005157 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005158 xmlHashDefaultDeallocator));
Daniel Veillard42766c02002-08-22 20:52:17 +00005159 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005160 xmlHashDefaultDeallocator));
Owen Taylor3473f882001-02-23 17:55:21 +00005161}
5162
5163/**
5164 * xmlXPathNsLookup:
5165 * @ctxt: the XPath context
5166 * @prefix: the namespace prefix value
5167 *
5168 * Search in the namespace declaration array of the context for the given
5169 * namespace name associated to the given prefix
5170 *
5171 * Returns the value or NULL if not found
5172 */
5173const xmlChar *
5174xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5175 if (ctxt == NULL)
5176 return(NULL);
5177 if (prefix == NULL)
5178 return(NULL);
5179
5180#ifdef XML_XML_NAMESPACE
5181 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5182 return(XML_XML_NAMESPACE);
5183#endif
5184
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005185 if (ctxt->namespaces != NULL) {
5186 int i;
5187
5188 for (i = 0;i < ctxt->nsNr;i++) {
5189 if ((ctxt->namespaces[i] != NULL) &&
5190 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5191 return(ctxt->namespaces[i]->href);
5192 }
5193 }
Owen Taylor3473f882001-02-23 17:55:21 +00005194
5195 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5196}
5197
5198/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005199 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005200 * @ctxt: the XPath context
5201 *
5202 * Cleanup the XPath context data associated to registered variables
5203 */
5204void
5205xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5206 if (ctxt == NULL)
5207 return;
5208
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005209 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
Owen Taylor3473f882001-02-23 17:55:21 +00005210 ctxt->nsHash = NULL;
5211}
5212
5213/************************************************************************
5214 * *
5215 * Routines to handle Values *
5216 * *
5217 ************************************************************************/
5218
William M. Brack08171912003-12-29 02:52:11 +00005219/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005220
5221/**
5222 * xmlXPathNewFloat:
5223 * @val: the double value
5224 *
5225 * Create a new xmlXPathObjectPtr of type double and of value @val
5226 *
5227 * Returns the newly created object.
5228 */
5229xmlXPathObjectPtr
5230xmlXPathNewFloat(double val) {
5231 xmlXPathObjectPtr ret;
5232
5233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5234 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005235 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005236 return(NULL);
5237 }
5238 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5239 ret->type = XPATH_NUMBER;
5240 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005241#ifdef XP_DEBUG_OBJ_USAGE
5242 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5243#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005244 return(ret);
5245}
5246
5247/**
5248 * xmlXPathNewBoolean:
5249 * @val: the boolean value
5250 *
5251 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5252 *
5253 * Returns the newly created object.
5254 */
5255xmlXPathObjectPtr
5256xmlXPathNewBoolean(int val) {
5257 xmlXPathObjectPtr ret;
5258
5259 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5260 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005261 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005262 return(NULL);
5263 }
5264 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5265 ret->type = XPATH_BOOLEAN;
5266 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005267#ifdef XP_DEBUG_OBJ_USAGE
5268 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5269#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005270 return(ret);
5271}
5272
5273/**
5274 * xmlXPathNewString:
5275 * @val: the xmlChar * value
5276 *
5277 * Create a new xmlXPathObjectPtr of type string and of value @val
5278 *
5279 * Returns the newly created object.
5280 */
5281xmlXPathObjectPtr
5282xmlXPathNewString(const xmlChar *val) {
5283 xmlXPathObjectPtr ret;
5284
5285 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5286 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005287 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005288 return(NULL);
5289 }
5290 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5291 ret->type = XPATH_STRING;
5292 if (val != NULL)
5293 ret->stringval = xmlStrdup(val);
5294 else
5295 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005296#ifdef XP_DEBUG_OBJ_USAGE
5297 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5298#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005299 return(ret);
5300}
5301
5302/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005303 * xmlXPathWrapString:
5304 * @val: the xmlChar * value
5305 *
5306 * Wraps the @val string into an XPath object.
5307 *
5308 * Returns the newly created object.
5309 */
5310xmlXPathObjectPtr
5311xmlXPathWrapString (xmlChar *val) {
5312 xmlXPathObjectPtr ret;
5313
5314 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5315 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005316 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005317 return(NULL);
5318 }
5319 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5320 ret->type = XPATH_STRING;
5321 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005322#ifdef XP_DEBUG_OBJ_USAGE
5323 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5324#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005325 return(ret);
5326}
5327
5328/**
Owen Taylor3473f882001-02-23 17:55:21 +00005329 * xmlXPathNewCString:
5330 * @val: the char * value
5331 *
5332 * Create a new xmlXPathObjectPtr of type string and of value @val
5333 *
5334 * Returns the newly created object.
5335 */
5336xmlXPathObjectPtr
5337xmlXPathNewCString(const char *val) {
5338 xmlXPathObjectPtr ret;
5339
5340 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5341 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005342 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005343 return(NULL);
5344 }
5345 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5346 ret->type = XPATH_STRING;
5347 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005348#ifdef XP_DEBUG_OBJ_USAGE
5349 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5350#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005351 return(ret);
5352}
5353
5354/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005355 * xmlXPathWrapCString:
5356 * @val: the char * value
5357 *
5358 * Wraps a string into an XPath object.
5359 *
5360 * Returns the newly created object.
5361 */
5362xmlXPathObjectPtr
5363xmlXPathWrapCString (char * val) {
5364 return(xmlXPathWrapString((xmlChar *)(val)));
5365}
5366
5367/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005368 * xmlXPathWrapExternal:
5369 * @val: the user data
5370 *
5371 * Wraps the @val data into an XPath object.
5372 *
5373 * Returns the newly created object.
5374 */
5375xmlXPathObjectPtr
5376xmlXPathWrapExternal (void *val) {
5377 xmlXPathObjectPtr ret;
5378
5379 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5380 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005381 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005382 return(NULL);
5383 }
5384 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5385 ret->type = XPATH_USERS;
5386 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005387#ifdef XP_DEBUG_OBJ_USAGE
5388 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5389#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005390 return(ret);
5391}
5392
5393/**
Owen Taylor3473f882001-02-23 17:55:21 +00005394 * xmlXPathObjectCopy:
5395 * @val: the original object
5396 *
5397 * allocate a new copy of a given object
5398 *
5399 * Returns the newly created object.
5400 */
5401xmlXPathObjectPtr
5402xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5403 xmlXPathObjectPtr ret;
5404
5405 if (val == NULL)
5406 return(NULL);
5407
5408 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5409 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005410 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005411 return(NULL);
5412 }
5413 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005414#ifdef XP_DEBUG_OBJ_USAGE
5415 xmlXPathDebugObjUsageRequested(NULL, val->type);
5416#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005417 switch (val->type) {
5418 case XPATH_BOOLEAN:
5419 case XPATH_NUMBER:
5420 case XPATH_POINT:
5421 case XPATH_RANGE:
5422 break;
5423 case XPATH_STRING:
5424 ret->stringval = xmlStrdup(val->stringval);
5425 break;
5426 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005427#if 0
5428/*
5429 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5430 this previous handling is no longer correct, and can cause some serious
5431 problems (ref. bug 145547)
5432*/
Owen Taylor3473f882001-02-23 17:55:21 +00005433 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005434 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005435 xmlNodePtr cur, tmp;
5436 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005437
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005438 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005439 top = xmlNewDoc(NULL);
5440 top->name = (char *)
5441 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005442 ret->user = top;
5443 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005444 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005445 cur = val->nodesetval->nodeTab[0]->children;
5446 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005447 tmp = xmlDocCopyNode(cur, top, 1);
5448 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005449 cur = cur->next;
5450 }
5451 }
William M. Bracke9449c52004-07-11 14:41:20 +00005452
Daniel Veillard9adc0462003-03-24 18:39:54 +00005453 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005454 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005455 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005456 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005457 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005458#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005459 case XPATH_NODESET:
5460 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005461 /* Do not deallocate the copied tree value */
5462 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005463 break;
5464 case XPATH_LOCATIONSET:
5465#ifdef LIBXML_XPTR_ENABLED
5466 {
5467 xmlLocationSetPtr loc = val->user;
5468 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5469 break;
5470 }
5471#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005472 case XPATH_USERS:
5473 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005474 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005475 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005476 xmlGenericError(xmlGenericErrorContext,
5477 "xmlXPathObjectCopy: unsupported type %d\n",
5478 val->type);
5479 break;
5480 }
5481 return(ret);
5482}
5483
5484/**
5485 * xmlXPathFreeObject:
5486 * @obj: the object to free
5487 *
5488 * Free up an xmlXPathObjectPtr object.
5489 */
5490void
5491xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5492 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005493 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005494 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005495#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005496 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005497 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005498 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005499 } else
5500#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005501 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005502 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005503 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005504 } else {
5505 if (obj->nodesetval != NULL)
5506 xmlXPathFreeNodeSet(obj->nodesetval);
5507 }
Owen Taylor3473f882001-02-23 17:55:21 +00005508#ifdef LIBXML_XPTR_ENABLED
5509 } else if (obj->type == XPATH_LOCATIONSET) {
5510 if (obj->user != NULL)
5511 xmlXPtrFreeLocationSet(obj->user);
5512#endif
5513 } else if (obj->type == XPATH_STRING) {
5514 if (obj->stringval != NULL)
5515 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005516 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005517#ifdef XP_DEBUG_OBJ_USAGE
5518 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5519#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005520 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005521}
Owen Taylor3473f882001-02-23 17:55:21 +00005522
Nick Wellnhofere03f0a12017-11-09 16:42:47 +01005523static void
5524xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5525 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5526}
5527
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005528/**
5529 * xmlXPathReleaseObject:
5530 * @obj: the xmlXPathObjectPtr to free or to cache
5531 *
5532 * Depending on the state of the cache this frees the given
5533 * XPath object or stores it in the cache.
5534 */
5535static void
5536xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5537{
5538#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5539 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5540 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5541
5542#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5543
5544 if (obj == NULL)
5545 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005546 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005547 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005548 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005549 xmlXPathContextCachePtr cache =
5550 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005551
5552 switch (obj->type) {
5553 case XPATH_NODESET:
5554 case XPATH_XSLT_TREE:
5555 if (obj->nodesetval != NULL) {
5556 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005557 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005558 * It looks like the @boolval is used for
5559 * evaluation if this an XSLT Result Tree Fragment.
5560 * TODO: Check if this assumption is correct.
5561 */
5562 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5563 xmlXPathFreeValueTree(obj->nodesetval);
5564 obj->nodesetval = NULL;
5565 } else if ((obj->nodesetval->nodeMax <= 40) &&
5566 (XP_CACHE_WANTS(cache->nodesetObjs,
5567 cache->maxNodeset)))
5568 {
5569 XP_CACHE_ADD(cache->nodesetObjs, obj);
5570 goto obj_cached;
5571 } else {
5572 xmlXPathFreeNodeSet(obj->nodesetval);
5573 obj->nodesetval = NULL;
5574 }
5575 }
5576 break;
5577 case XPATH_STRING:
5578 if (obj->stringval != NULL)
5579 xmlFree(obj->stringval);
5580
5581 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5582 XP_CACHE_ADD(cache->stringObjs, obj);
5583 goto obj_cached;
5584 }
5585 break;
5586 case XPATH_BOOLEAN:
5587 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5588 XP_CACHE_ADD(cache->booleanObjs, obj);
5589 goto obj_cached;
5590 }
5591 break;
5592 case XPATH_NUMBER:
5593 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5594 XP_CACHE_ADD(cache->numberObjs, obj);
5595 goto obj_cached;
5596 }
5597 break;
5598#ifdef LIBXML_XPTR_ENABLED
5599 case XPATH_LOCATIONSET:
5600 if (obj->user != NULL) {
5601 xmlXPtrFreeLocationSet(obj->user);
5602 }
5603 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005604#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005605 default:
5606 goto free_obj;
5607 }
5608
5609 /*
5610 * Fallback to adding to the misc-objects slot.
5611 */
5612 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5613 XP_CACHE_ADD(cache->miscObjs, obj);
5614 } else
5615 goto free_obj;
5616
5617obj_cached:
5618
5619#ifdef XP_DEBUG_OBJ_USAGE
5620 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5621#endif
5622
5623 if (obj->nodesetval != NULL) {
5624 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005625
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005626 /*
5627 * TODO: Due to those nasty ns-nodes, we need to traverse
5628 * the list and free the ns-nodes.
5629 * URGENT TODO: Check if it's actually slowing things down.
5630 * Maybe we shouldn't try to preserve the list.
5631 */
5632 if (tmpset->nodeNr > 1) {
5633 int i;
5634 xmlNodePtr node;
5635
5636 for (i = 0; i < tmpset->nodeNr; i++) {
5637 node = tmpset->nodeTab[i];
5638 if ((node != NULL) &&
5639 (node->type == XML_NAMESPACE_DECL))
5640 {
5641 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5642 }
5643 }
5644 } else if (tmpset->nodeNr == 1) {
5645 if ((tmpset->nodeTab[0] != NULL) &&
5646 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5647 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005648 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005649 tmpset->nodeNr = 0;
5650 memset(obj, 0, sizeof(xmlXPathObject));
5651 obj->nodesetval = tmpset;
5652 } else
5653 memset(obj, 0, sizeof(xmlXPathObject));
5654
5655 return;
5656
5657free_obj:
5658 /*
5659 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005660 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005661 if (obj->nodesetval != NULL)
5662 xmlXPathFreeNodeSet(obj->nodesetval);
5663#ifdef XP_DEBUG_OBJ_USAGE
5664 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5665#endif
5666 xmlFree(obj);
5667 }
5668 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005669}
5670
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005671
5672/************************************************************************
5673 * *
5674 * Type Casting Routines *
5675 * *
5676 ************************************************************************/
5677
5678/**
5679 * xmlXPathCastBooleanToString:
5680 * @val: a boolean
5681 *
5682 * Converts a boolean to its string value.
5683 *
5684 * Returns a newly allocated string.
5685 */
5686xmlChar *
5687xmlXPathCastBooleanToString (int val) {
5688 xmlChar *ret;
5689 if (val)
5690 ret = xmlStrdup((const xmlChar *) "true");
5691 else
5692 ret = xmlStrdup((const xmlChar *) "false");
5693 return(ret);
5694}
5695
5696/**
5697 * xmlXPathCastNumberToString:
5698 * @val: a number
5699 *
5700 * Converts a number to its string value.
5701 *
5702 * Returns a newly allocated string.
5703 */
5704xmlChar *
5705xmlXPathCastNumberToString (double val) {
5706 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005707 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005708 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005709 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005710 break;
5711 case -1:
5712 ret = xmlStrdup((const xmlChar *) "-Infinity");
5713 break;
5714 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005715 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005716 ret = xmlStrdup((const xmlChar *) "NaN");
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005717 } else if (val == 0) {
5718 /* Omit sign for negative zero. */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005719 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005720 } else {
5721 /* could be improved */
5722 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005723 xmlXPathFormatNumber(val, buf, 99);
5724 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005725 ret = xmlStrdup((const xmlChar *) buf);
5726 }
5727 }
5728 return(ret);
5729}
5730
5731/**
5732 * xmlXPathCastNodeToString:
5733 * @node: a node
5734 *
5735 * Converts a node to its string value.
5736 *
5737 * Returns a newly allocated string.
5738 */
5739xmlChar *
5740xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005741xmlChar *ret;
5742 if ((ret = xmlNodeGetContent(node)) == NULL)
5743 ret = xmlStrdup((const xmlChar *) "");
5744 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005745}
5746
5747/**
5748 * xmlXPathCastNodeSetToString:
5749 * @ns: a node-set
5750 *
5751 * Converts a node-set to its string value.
5752 *
5753 * Returns a newly allocated string.
5754 */
5755xmlChar *
5756xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5757 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5758 return(xmlStrdup((const xmlChar *) ""));
5759
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005760 if (ns->nodeNr > 1)
5761 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005762 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5763}
5764
5765/**
5766 * xmlXPathCastToString:
5767 * @val: an XPath object
5768 *
5769 * Converts an existing object to its string() equivalent
5770 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005771 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005772 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005773 */
5774xmlChar *
5775xmlXPathCastToString(xmlXPathObjectPtr val) {
5776 xmlChar *ret = NULL;
5777
5778 if (val == NULL)
5779 return(xmlStrdup((const xmlChar *) ""));
5780 switch (val->type) {
5781 case XPATH_UNDEFINED:
5782#ifdef DEBUG_EXPR
5783 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5784#endif
5785 ret = xmlStrdup((const xmlChar *) "");
5786 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005787 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005788 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005789 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5790 break;
5791 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005792 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005793 case XPATH_BOOLEAN:
5794 ret = xmlXPathCastBooleanToString(val->boolval);
5795 break;
5796 case XPATH_NUMBER: {
5797 ret = xmlXPathCastNumberToString(val->floatval);
5798 break;
5799 }
5800 case XPATH_USERS:
5801 case XPATH_POINT:
5802 case XPATH_RANGE:
5803 case XPATH_LOCATIONSET:
5804 TODO
5805 ret = xmlStrdup((const xmlChar *) "");
5806 break;
5807 }
5808 return(ret);
5809}
5810
5811/**
5812 * xmlXPathConvertString:
5813 * @val: an XPath object
5814 *
5815 * Converts an existing object to its string() equivalent
5816 *
5817 * Returns the new object, the old one is freed (or the operation
5818 * is done directly on @val)
5819 */
5820xmlXPathObjectPtr
5821xmlXPathConvertString(xmlXPathObjectPtr val) {
5822 xmlChar *res = NULL;
5823
5824 if (val == NULL)
5825 return(xmlXPathNewCString(""));
5826
5827 switch (val->type) {
5828 case XPATH_UNDEFINED:
5829#ifdef DEBUG_EXPR
5830 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5831#endif
5832 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005833 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005834 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005835 res = xmlXPathCastNodeSetToString(val->nodesetval);
5836 break;
5837 case XPATH_STRING:
5838 return(val);
5839 case XPATH_BOOLEAN:
5840 res = xmlXPathCastBooleanToString(val->boolval);
5841 break;
5842 case XPATH_NUMBER:
5843 res = xmlXPathCastNumberToString(val->floatval);
5844 break;
5845 case XPATH_USERS:
5846 case XPATH_POINT:
5847 case XPATH_RANGE:
5848 case XPATH_LOCATIONSET:
5849 TODO;
5850 break;
5851 }
5852 xmlXPathFreeObject(val);
5853 if (res == NULL)
5854 return(xmlXPathNewCString(""));
5855 return(xmlXPathWrapString(res));
5856}
5857
5858/**
5859 * xmlXPathCastBooleanToNumber:
5860 * @val: a boolean
5861 *
5862 * Converts a boolean to its number value
5863 *
5864 * Returns the number value
5865 */
5866double
5867xmlXPathCastBooleanToNumber(int val) {
5868 if (val)
5869 return(1.0);
5870 return(0.0);
5871}
5872
5873/**
5874 * xmlXPathCastStringToNumber:
5875 * @val: a string
5876 *
5877 * Converts a string to its number value
5878 *
5879 * Returns the number value
5880 */
5881double
5882xmlXPathCastStringToNumber(const xmlChar * val) {
5883 return(xmlXPathStringEvalNumber(val));
5884}
5885
5886/**
5887 * xmlXPathCastNodeToNumber:
5888 * @node: a node
5889 *
5890 * Converts a node to its number value
5891 *
5892 * Returns the number value
5893 */
5894double
5895xmlXPathCastNodeToNumber (xmlNodePtr node) {
5896 xmlChar *strval;
5897 double ret;
5898
5899 if (node == NULL)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005900 return(NAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005901 strval = xmlXPathCastNodeToString(node);
5902 if (strval == NULL)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005903 return(NAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005904 ret = xmlXPathCastStringToNumber(strval);
5905 xmlFree(strval);
5906
5907 return(ret);
5908}
5909
5910/**
5911 * xmlXPathCastNodeSetToNumber:
5912 * @ns: a node-set
5913 *
5914 * Converts a node-set to its number value
5915 *
5916 * Returns the number value
5917 */
5918double
5919xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5920 xmlChar *str;
5921 double ret;
5922
5923 if (ns == NULL)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005924 return(NAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005925 str = xmlXPathCastNodeSetToString(ns);
5926 ret = xmlXPathCastStringToNumber(str);
5927 xmlFree(str);
5928 return(ret);
5929}
5930
5931/**
5932 * xmlXPathCastToNumber:
5933 * @val: an XPath object
5934 *
5935 * Converts an XPath object to its number value
5936 *
5937 * Returns the number value
5938 */
5939double
5940xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5941 double ret = 0.0;
5942
5943 if (val == NULL)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005944 return(NAN);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005945 switch (val->type) {
5946 case XPATH_UNDEFINED:
5947#ifdef DEGUB_EXPR
5948 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5949#endif
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005950 ret = NAN;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005951 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005952 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005953 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005954 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5955 break;
5956 case XPATH_STRING:
5957 ret = xmlXPathCastStringToNumber(val->stringval);
5958 break;
5959 case XPATH_NUMBER:
5960 ret = val->floatval;
5961 break;
5962 case XPATH_BOOLEAN:
5963 ret = xmlXPathCastBooleanToNumber(val->boolval);
5964 break;
5965 case XPATH_USERS:
5966 case XPATH_POINT:
5967 case XPATH_RANGE:
5968 case XPATH_LOCATIONSET:
5969 TODO;
Nick Wellnhofer8813f392017-09-21 00:11:26 +02005970 ret = NAN;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005971 break;
5972 }
5973 return(ret);
5974}
5975
5976/**
5977 * xmlXPathConvertNumber:
5978 * @val: an XPath object
5979 *
5980 * Converts an existing object to its number() equivalent
5981 *
5982 * Returns the new object, the old one is freed (or the operation
5983 * is done directly on @val)
5984 */
5985xmlXPathObjectPtr
5986xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5987 xmlXPathObjectPtr ret;
5988
5989 if (val == NULL)
5990 return(xmlXPathNewFloat(0.0));
5991 if (val->type == XPATH_NUMBER)
5992 return(val);
5993 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5994 xmlXPathFreeObject(val);
5995 return(ret);
5996}
5997
5998/**
5999 * xmlXPathCastNumberToBoolean:
6000 * @val: a number
6001 *
6002 * Converts a number to its boolean value
6003 *
6004 * Returns the boolean value
6005 */
6006int
6007xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00006008 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006009 return(0);
6010 return(1);
6011}
6012
6013/**
6014 * xmlXPathCastStringToBoolean:
6015 * @val: a string
6016 *
6017 * Converts a string to its boolean value
6018 *
6019 * Returns the boolean value
6020 */
6021int
6022xmlXPathCastStringToBoolean (const xmlChar *val) {
6023 if ((val == NULL) || (xmlStrlen(val) == 0))
6024 return(0);
6025 return(1);
6026}
6027
6028/**
6029 * xmlXPathCastNodeSetToBoolean:
6030 * @ns: a node-set
6031 *
6032 * Converts a node-set to its boolean value
6033 *
6034 * Returns the boolean value
6035 */
6036int
6037xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6038 if ((ns == NULL) || (ns->nodeNr == 0))
6039 return(0);
6040 return(1);
6041}
6042
6043/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006044 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006045 * @val: an XPath object
6046 *
6047 * Converts an XPath object to its boolean value
6048 *
6049 * Returns the boolean value
6050 */
6051int
6052xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6053 int ret = 0;
6054
6055 if (val == NULL)
6056 return(0);
6057 switch (val->type) {
6058 case XPATH_UNDEFINED:
6059#ifdef DEBUG_EXPR
6060 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6061#endif
6062 ret = 0;
6063 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006064 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00006065 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006066 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6067 break;
6068 case XPATH_STRING:
6069 ret = xmlXPathCastStringToBoolean(val->stringval);
6070 break;
6071 case XPATH_NUMBER:
6072 ret = xmlXPathCastNumberToBoolean(val->floatval);
6073 break;
6074 case XPATH_BOOLEAN:
6075 ret = val->boolval;
6076 break;
6077 case XPATH_USERS:
6078 case XPATH_POINT:
6079 case XPATH_RANGE:
6080 case XPATH_LOCATIONSET:
6081 TODO;
6082 ret = 0;
6083 break;
6084 }
6085 return(ret);
6086}
6087
6088
6089/**
6090 * xmlXPathConvertBoolean:
6091 * @val: an XPath object
6092 *
6093 * Converts an existing object to its boolean() equivalent
6094 *
6095 * Returns the new object, the old one is freed (or the operation
6096 * is done directly on @val)
6097 */
6098xmlXPathObjectPtr
6099xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6100 xmlXPathObjectPtr ret;
6101
6102 if (val == NULL)
6103 return(xmlXPathNewBoolean(0));
6104 if (val->type == XPATH_BOOLEAN)
6105 return(val);
6106 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6107 xmlXPathFreeObject(val);
6108 return(ret);
6109}
6110
Owen Taylor3473f882001-02-23 17:55:21 +00006111/************************************************************************
6112 * *
6113 * Routines to handle XPath contexts *
6114 * *
6115 ************************************************************************/
6116
6117/**
6118 * xmlXPathNewContext:
6119 * @doc: the XML document
6120 *
6121 * Create a new xmlXPathContext
6122 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006123 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006124 */
6125xmlXPathContextPtr
6126xmlXPathNewContext(xmlDocPtr doc) {
6127 xmlXPathContextPtr ret;
6128
6129 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6130 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006131 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006132 return(NULL);
6133 }
6134 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6135 ret->doc = doc;
6136 ret->node = NULL;
6137
6138 ret->varHash = NULL;
6139
6140 ret->nb_types = 0;
6141 ret->max_types = 0;
6142 ret->types = NULL;
6143
6144 ret->funcHash = xmlHashCreate(0);
6145
6146 ret->nb_axis = 0;
6147 ret->max_axis = 0;
6148 ret->axis = NULL;
6149
6150 ret->nsHash = NULL;
6151 ret->user = NULL;
6152
6153 ret->contextSize = -1;
6154 ret->proximityPosition = -1;
6155
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006156#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006157 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006158 xmlXPathFreeContext(ret);
6159 return(NULL);
6160 }
6161#endif
6162
Daniel Veillard45490ae2008-07-29 09:13:19 +00006163 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006164
Owen Taylor3473f882001-02-23 17:55:21 +00006165 return(ret);
6166}
6167
6168/**
6169 * xmlXPathFreeContext:
6170 * @ctxt: the context to free
6171 *
6172 * Free up an xmlXPathContext
6173 */
6174void
6175xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006176 if (ctxt == NULL) return;
6177
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006178 if (ctxt->cache != NULL)
6179 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006180 xmlXPathRegisteredNsCleanup(ctxt);
6181 xmlXPathRegisteredFuncsCleanup(ctxt);
6182 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006183 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006184 xmlFree(ctxt);
6185}
6186
6187/************************************************************************
6188 * *
6189 * Routines to handle XPath parser contexts *
6190 * *
6191 ************************************************************************/
6192
6193#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006194 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006195 __xmlRaiseError(NULL, NULL, NULL, \
6196 NULL, NULL, XML_FROM_XPATH, \
6197 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6198 __FILE__, __LINE__, \
6199 NULL, NULL, NULL, 0, 0, \
6200 "NULL context pointer\n"); \
6201 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006202 } \
6203
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006204#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006205 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006206 __xmlRaiseError(NULL, NULL, NULL, \
6207 NULL, NULL, XML_FROM_XPATH, \
6208 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6209 __FILE__, __LINE__, \
6210 NULL, NULL, NULL, 0, 0, \
6211 "NULL context pointer\n"); \
6212 return(-1); \
6213 } \
6214
Owen Taylor3473f882001-02-23 17:55:21 +00006215
6216#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006217 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006218 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006219 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006220 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006221 }
Owen Taylor3473f882001-02-23 17:55:21 +00006222
6223
6224/**
6225 * xmlXPathNewParserContext:
6226 * @str: the XPath expression
6227 * @ctxt: the XPath context
6228 *
6229 * Create a new xmlXPathParserContext
6230 *
6231 * Returns the xmlXPathParserContext just allocated.
6232 */
6233xmlXPathParserContextPtr
6234xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6235 xmlXPathParserContextPtr ret;
6236
6237 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6238 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006239 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006240 return(NULL);
6241 }
6242 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6243 ret->cur = ret->base = str;
6244 ret->context = ctxt;
6245
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006246 ret->comp = xmlXPathNewCompExpr();
6247 if (ret->comp == NULL) {
6248 xmlFree(ret->valueTab);
6249 xmlFree(ret);
6250 return(NULL);
6251 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006252 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6253 ret->comp->dict = ctxt->dict;
6254 xmlDictReference(ret->comp->dict);
6255 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006256
6257 return(ret);
6258}
6259
6260/**
6261 * xmlXPathCompParserContext:
6262 * @comp: the XPath compiled expression
6263 * @ctxt: the XPath context
6264 *
6265 * Create a new xmlXPathParserContext when processing a compiled expression
6266 *
6267 * Returns the xmlXPathParserContext just allocated.
6268 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006269static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006270xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6271 xmlXPathParserContextPtr ret;
6272
6273 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6274 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006275 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006276 return(NULL);
6277 }
6278 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6279
Owen Taylor3473f882001-02-23 17:55:21 +00006280 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006281 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006282 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006283 if (ret->valueTab == NULL) {
6284 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006285 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006286 return(NULL);
6287 }
Owen Taylor3473f882001-02-23 17:55:21 +00006288 ret->valueNr = 0;
6289 ret->valueMax = 10;
6290 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006291 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006292
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006293 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006294 ret->comp = comp;
6295
Owen Taylor3473f882001-02-23 17:55:21 +00006296 return(ret);
6297}
6298
6299/**
6300 * xmlXPathFreeParserContext:
6301 * @ctxt: the context to free
6302 *
6303 * Free up an xmlXPathParserContext
6304 */
6305void
6306xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006307 int i;
6308
Owen Taylor3473f882001-02-23 17:55:21 +00006309 if (ctxt->valueTab != NULL) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006310 for (i = 0; i < ctxt->valueNr; i++) {
6311 if (ctxt->context)
6312 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6313 else
6314 xmlXPathFreeObject(ctxt->valueTab[i]);
6315 }
Owen Taylor3473f882001-02-23 17:55:21 +00006316 xmlFree(ctxt->valueTab);
6317 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006318 if (ctxt->comp != NULL) {
6319#ifdef XPATH_STREAMING
6320 if (ctxt->comp->stream != NULL) {
6321 xmlFreePatternList(ctxt->comp->stream);
6322 ctxt->comp->stream = NULL;
6323 }
6324#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006325 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006326 }
Owen Taylor3473f882001-02-23 17:55:21 +00006327 xmlFree(ctxt);
6328}
6329
6330/************************************************************************
6331 * *
6332 * The implicit core function library *
6333 * *
6334 ************************************************************************/
6335
Owen Taylor3473f882001-02-23 17:55:21 +00006336/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006337 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006338 * @node: a node pointer
6339 *
6340 * Function computing the beginning of the string value of the node,
6341 * used to speed up comparisons
6342 *
6343 * Returns an int usable as a hash
6344 */
6345static unsigned int
6346xmlXPathNodeValHash(xmlNodePtr node) {
6347 int len = 2;
6348 const xmlChar * string = NULL;
6349 xmlNodePtr tmp = NULL;
6350 unsigned int ret = 0;
6351
6352 if (node == NULL)
6353 return(0);
6354
Daniel Veillard9adc0462003-03-24 18:39:54 +00006355 if (node->type == XML_DOCUMENT_NODE) {
6356 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6357 if (tmp == NULL)
6358 node = node->children;
6359 else
6360 node = tmp;
6361
6362 if (node == NULL)
6363 return(0);
6364 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006365
6366 switch (node->type) {
6367 case XML_COMMENT_NODE:
6368 case XML_PI_NODE:
6369 case XML_CDATA_SECTION_NODE:
6370 case XML_TEXT_NODE:
6371 string = node->content;
6372 if (string == NULL)
6373 return(0);
6374 if (string[0] == 0)
6375 return(0);
6376 return(((unsigned int) string[0]) +
6377 (((unsigned int) string[1]) << 8));
6378 case XML_NAMESPACE_DECL:
6379 string = ((xmlNsPtr)node)->href;
6380 if (string == NULL)
6381 return(0);
6382 if (string[0] == 0)
6383 return(0);
6384 return(((unsigned int) string[0]) +
6385 (((unsigned int) string[1]) << 8));
6386 case XML_ATTRIBUTE_NODE:
6387 tmp = ((xmlAttrPtr) node)->children;
6388 break;
6389 case XML_ELEMENT_NODE:
6390 tmp = node->children;
6391 break;
6392 default:
6393 return(0);
6394 }
6395 while (tmp != NULL) {
6396 switch (tmp->type) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006397 case XML_CDATA_SECTION_NODE:
6398 case XML_TEXT_NODE:
6399 string = tmp->content;
6400 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006401 default:
Nick Wellnhofer5af594d2017-10-07 14:54:45 +02006402 string = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006403 break;
6404 }
6405 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006406 if (len == 1) {
6407 return(ret + (((unsigned int) string[0]) << 8));
6408 }
6409 if (string[1] == 0) {
6410 len = 1;
6411 ret = (unsigned int) string[0];
6412 } else {
6413 return(((unsigned int) string[0]) +
6414 (((unsigned int) string[1]) << 8));
6415 }
6416 }
6417 /*
6418 * Skip to next node
6419 */
6420 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6421 if (tmp->children->type != XML_ENTITY_DECL) {
6422 tmp = tmp->children;
6423 continue;
6424 }
6425 }
6426 if (tmp == node)
6427 break;
6428
6429 if (tmp->next != NULL) {
6430 tmp = tmp->next;
6431 continue;
6432 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006433
Daniel Veillardf06307e2001-07-03 10:35:50 +00006434 do {
6435 tmp = tmp->parent;
6436 if (tmp == NULL)
6437 break;
6438 if (tmp == node) {
6439 tmp = NULL;
6440 break;
6441 }
6442 if (tmp->next != NULL) {
6443 tmp = tmp->next;
6444 break;
6445 }
6446 } while (tmp != NULL);
6447 }
6448 return(ret);
6449}
6450
6451/**
6452 * xmlXPathStringHash:
6453 * @string: a string
6454 *
6455 * Function computing the beginning of the string value of the node,
6456 * used to speed up comparisons
6457 *
6458 * Returns an int usable as a hash
6459 */
6460static unsigned int
6461xmlXPathStringHash(const xmlChar * string) {
6462 if (string == NULL)
6463 return((unsigned int) 0);
6464 if (string[0] == 0)
6465 return(0);
6466 return(((unsigned int) string[0]) +
6467 (((unsigned int) string[1]) << 8));
6468}
6469
6470/**
Owen Taylor3473f882001-02-23 17:55:21 +00006471 * xmlXPathCompareNodeSetFloat:
6472 * @ctxt: the XPath Parser context
6473 * @inf: less than (1) or greater than (0)
6474 * @strict: is the comparison strict
6475 * @arg: the node set
6476 * @f: the value
6477 *
6478 * Implement the compare operation between a nodeset and a number
6479 * @ns < @val (1, 1, ...
6480 * @ns <= @val (1, 0, ...
6481 * @ns > @val (0, 1, ...
6482 * @ns >= @val (0, 0, ...
6483 *
6484 * If one object to be compared is a node-set and the other is a number,
6485 * then the comparison will be true if and only if there is a node in the
6486 * node-set such that the result of performing the comparison on the number
6487 * to be compared and on the result of converting the string-value of that
6488 * node to a number using the number function is true.
6489 *
6490 * Returns 0 or 1 depending on the results of the test.
6491 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006492static int
Owen Taylor3473f882001-02-23 17:55:21 +00006493xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6494 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6495 int i, ret = 0;
6496 xmlNodeSetPtr ns;
6497 xmlChar *str2;
6498
6499 if ((f == NULL) || (arg == NULL) ||
6500 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006501 xmlXPathReleaseObject(ctxt->context, arg);
6502 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006503 return(0);
6504 }
6505 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006506 if (ns != NULL) {
6507 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006508 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006509 if (str2 != NULL) {
6510 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006511 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006512 xmlFree(str2);
6513 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006514 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006515 ret = xmlXPathCompareValues(ctxt, inf, strict);
6516 if (ret)
6517 break;
6518 }
6519 }
Owen Taylor3473f882001-02-23 17:55:21 +00006520 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006521 xmlXPathReleaseObject(ctxt->context, arg);
6522 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006523 return(ret);
6524}
6525
6526/**
6527 * xmlXPathCompareNodeSetString:
6528 * @ctxt: the XPath Parser context
6529 * @inf: less than (1) or greater than (0)
6530 * @strict: is the comparison strict
6531 * @arg: the node set
6532 * @s: the value
6533 *
6534 * Implement the compare operation between a nodeset and a string
6535 * @ns < @val (1, 1, ...
6536 * @ns <= @val (1, 0, ...
6537 * @ns > @val (0, 1, ...
6538 * @ns >= @val (0, 0, ...
6539 *
6540 * If one object to be compared is a node-set and the other is a string,
6541 * then the comparison will be true if and only if there is a node in
6542 * the node-set such that the result of performing the comparison on the
6543 * string-value of the node and the other string is true.
6544 *
6545 * Returns 0 or 1 depending on the results of the test.
6546 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006547static int
Owen Taylor3473f882001-02-23 17:55:21 +00006548xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6549 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6550 int i, ret = 0;
6551 xmlNodeSetPtr ns;
6552 xmlChar *str2;
6553
6554 if ((s == NULL) || (arg == NULL) ||
6555 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006556 xmlXPathReleaseObject(ctxt->context, arg);
6557 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006558 return(0);
6559 }
6560 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006561 if (ns != NULL) {
6562 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006563 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006564 if (str2 != NULL) {
6565 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006566 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006567 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006568 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006569 ret = xmlXPathCompareValues(ctxt, inf, strict);
6570 if (ret)
6571 break;
6572 }
6573 }
Owen Taylor3473f882001-02-23 17:55:21 +00006574 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006575 xmlXPathReleaseObject(ctxt->context, arg);
6576 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006577 return(ret);
6578}
6579
6580/**
6581 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006582 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006583 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006584 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006585 * @arg2: the second node set object
6586 *
6587 * Implement the compare operation on nodesets:
6588 *
6589 * If both objects to be compared are node-sets, then the comparison
6590 * will be true if and only if there is a node in the first node-set
6591 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006592 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006593 * ....
6594 * When neither object to be compared is a node-set and the operator
6595 * is <=, <, >= or >, then the objects are compared by converting both
6596 * objects to numbers and comparing the numbers according to IEEE 754.
6597 * ....
6598 * The number function converts its argument to a number as follows:
6599 * - a string that consists of optional whitespace followed by an
6600 * optional minus sign followed by a Number followed by whitespace
6601 * is converted to the IEEE 754 number that is nearest (according
6602 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6603 * represented by the string; any other string is converted to NaN
6604 *
6605 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006606 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006607 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006608static int
6609xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006610 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6611 int i, j, init = 0;
6612 double val1;
6613 double *values2;
6614 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006615 xmlNodeSetPtr ns1;
6616 xmlNodeSetPtr ns2;
6617
6618 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006619 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6620 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006621 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006622 }
Owen Taylor3473f882001-02-23 17:55:21 +00006623 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006624 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6625 xmlXPathFreeObject(arg1);
6626 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006627 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006628 }
Owen Taylor3473f882001-02-23 17:55:21 +00006629
6630 ns1 = arg1->nodesetval;
6631 ns2 = arg2->nodesetval;
6632
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006633 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006634 xmlXPathFreeObject(arg1);
6635 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006636 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006637 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006638 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006639 xmlXPathFreeObject(arg1);
6640 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006641 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006642 }
Owen Taylor3473f882001-02-23 17:55:21 +00006643
6644 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6645 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006646 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006647 xmlXPathFreeObject(arg1);
6648 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006649 return(0);
6650 }
6651 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006652 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006653 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006654 continue;
6655 for (j = 0;j < ns2->nodeNr;j++) {
6656 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006657 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006658 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006659 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006660 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006661 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006662 ret = (val1 < values2[j]);
6663 else if (inf && !strict)
6664 ret = (val1 <= values2[j]);
6665 else if (!inf && strict)
6666 ret = (val1 > values2[j]);
6667 else if (!inf && !strict)
6668 ret = (val1 >= values2[j]);
6669 if (ret)
6670 break;
6671 }
6672 if (ret)
6673 break;
6674 init = 1;
6675 }
6676 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006677 xmlXPathFreeObject(arg1);
6678 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006679 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006680}
6681
6682/**
6683 * xmlXPathCompareNodeSetValue:
6684 * @ctxt: the XPath Parser context
6685 * @inf: less than (1) or greater than (0)
6686 * @strict: is the comparison strict
6687 * @arg: the node set
6688 * @val: the value
6689 *
6690 * Implement the compare operation between a nodeset and a value
6691 * @ns < @val (1, 1, ...
6692 * @ns <= @val (1, 0, ...
6693 * @ns > @val (0, 1, ...
6694 * @ns >= @val (0, 0, ...
6695 *
6696 * If one object to be compared is a node-set and the other is a boolean,
6697 * then the comparison will be true if and only if the result of performing
6698 * the comparison on the boolean and on the result of converting
6699 * the node-set to a boolean using the boolean function is true.
6700 *
6701 * Returns 0 or 1 depending on the results of the test.
6702 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006703static int
Owen Taylor3473f882001-02-23 17:55:21 +00006704xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6705 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6706 if ((val == NULL) || (arg == NULL) ||
6707 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6708 return(0);
6709
6710 switch(val->type) {
6711 case XPATH_NUMBER:
6712 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6713 case XPATH_NODESET:
6714 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006715 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006716 case XPATH_STRING:
6717 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6718 case XPATH_BOOLEAN:
6719 valuePush(ctxt, arg);
6720 xmlXPathBooleanFunction(ctxt, 1);
6721 valuePush(ctxt, val);
6722 return(xmlXPathCompareValues(ctxt, inf, strict));
6723 default:
Nick Wellnhofercf60dbe2017-05-25 16:20:56 +02006724 xmlGenericError(xmlGenericErrorContext,
6725 "xmlXPathCompareNodeSetValue: Can't compare node set "
6726 "and object of type %d\n",
6727 val->type);
6728 xmlXPathReleaseObject(ctxt->context, arg);
6729 xmlXPathReleaseObject(ctxt->context, val);
6730 XP_ERROR0(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006731 }
6732 return(0);
6733}
6734
6735/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006736 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006737 * @arg: the nodeset object argument
6738 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006739 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006740 *
6741 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6742 * If one object to be compared is a node-set and the other is a string,
6743 * then the comparison will be true if and only if there is a node in
6744 * the node-set such that the result of performing the comparison on the
6745 * string-value of the node and the other string is true.
6746 *
6747 * Returns 0 or 1 depending on the results of the test.
6748 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006749static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006750xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006751{
Owen Taylor3473f882001-02-23 17:55:21 +00006752 int i;
6753 xmlNodeSetPtr ns;
6754 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006755 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006756
6757 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006758 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6759 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006760 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006761 /*
6762 * A NULL nodeset compared with a string is always false
6763 * (since there is no node equal, and no node not equal)
6764 */
6765 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006766 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006767 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006768 for (i = 0; i < ns->nodeNr; i++) {
6769 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6770 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6771 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6772 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006773 if (neq)
6774 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006775 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006776 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6777 if (neq)
6778 continue;
6779 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006780 } else if (neq) {
6781 if (str2 != NULL)
6782 xmlFree(str2);
6783 return (1);
6784 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006785 if (str2 != NULL)
6786 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006787 } else if (neq)
6788 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006789 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006790 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006791}
6792
6793/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006794 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006795 * @arg: the nodeset object argument
6796 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006797 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006798 *
6799 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6800 * If one object to be compared is a node-set and the other is a number,
6801 * then the comparison will be true if and only if there is a node in
6802 * the node-set such that the result of performing the comparison on the
6803 * number to be compared and on the result of converting the string-value
6804 * of that node to a number using the number function is true.
6805 *
6806 * Returns 0 or 1 depending on the results of the test.
6807 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006808static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006809xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6810 xmlXPathObjectPtr arg, double f, int neq) {
6811 int i, ret=0;
6812 xmlNodeSetPtr ns;
6813 xmlChar *str2;
6814 xmlXPathObjectPtr val;
6815 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006816
6817 if ((arg == NULL) ||
6818 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6819 return(0);
6820
William M. Brack0c022ad2002-07-12 00:56:01 +00006821 ns = arg->nodesetval;
6822 if (ns != NULL) {
6823 for (i=0;i<ns->nodeNr;i++) {
6824 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6825 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006826 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006827 xmlFree(str2);
6828 xmlXPathNumberFunction(ctxt, 1);
6829 val = valuePop(ctxt);
6830 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006831 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006832 if (!xmlXPathIsNaN(v)) {
6833 if ((!neq) && (v==f)) {
6834 ret = 1;
6835 break;
6836 } else if ((neq) && (v!=f)) {
6837 ret = 1;
6838 break;
6839 }
William M. Brack32f0f712005-07-14 07:00:33 +00006840 } else { /* NaN is unequal to any value */
6841 if (neq)
6842 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006843 }
6844 }
6845 }
6846 }
6847
6848 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006849}
6850
6851
6852/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006853 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006854 * @arg1: first nodeset object argument
6855 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006856 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006857 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006858 * Implement the equal / not equal operation on XPath nodesets:
6859 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006860 * If both objects to be compared are node-sets, then the comparison
6861 * will be true if and only if there is a node in the first node-set and
6862 * a node in the second node-set such that the result of performing the
6863 * comparison on the string-values of the two nodes is true.
6864 *
6865 * (needless to say, this is a costly operation)
6866 *
6867 * Returns 0 or 1 depending on the results of the test.
6868 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006869static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006870xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006871 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006872 unsigned int *hashs1;
6873 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006874 xmlChar **values1;
6875 xmlChar **values2;
6876 int ret = 0;
6877 xmlNodeSetPtr ns1;
6878 xmlNodeSetPtr ns2;
6879
6880 if ((arg1 == NULL) ||
6881 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6882 return(0);
6883 if ((arg2 == NULL) ||
6884 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6885 return(0);
6886
6887 ns1 = arg1->nodesetval;
6888 ns2 = arg2->nodesetval;
6889
Daniel Veillard911f49a2001-04-07 15:39:35 +00006890 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006891 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006892 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006893 return(0);
6894
6895 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006896 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006897 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006898 if (neq == 0)
6899 for (i = 0;i < ns1->nodeNr;i++)
6900 for (j = 0;j < ns2->nodeNr;j++)
6901 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6902 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006903
6904 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006905 if (values1 == NULL) {
6906 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006907 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006908 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006909 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6910 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006911 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006912 xmlFree(values1);
6913 return(0);
6914 }
Owen Taylor3473f882001-02-23 17:55:21 +00006915 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6916 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6917 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006918 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006919 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006920 xmlFree(values1);
6921 return(0);
6922 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006923 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6924 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006925 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006926 xmlFree(hashs1);
6927 xmlFree(values1);
6928 xmlFree(values2);
6929 return(0);
6930 }
Owen Taylor3473f882001-02-23 17:55:21 +00006931 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6932 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006933 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006934 for (j = 0;j < ns2->nodeNr;j++) {
6935 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006936 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006937 if (hashs1[i] != hashs2[j]) {
6938 if (neq) {
6939 ret = 1;
6940 break;
6941 }
6942 }
6943 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006944 if (values1[i] == NULL)
6945 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6946 if (values2[j] == NULL)
6947 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006948 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006949 if (ret)
6950 break;
6951 }
Owen Taylor3473f882001-02-23 17:55:21 +00006952 }
6953 if (ret)
6954 break;
6955 }
6956 for (i = 0;i < ns1->nodeNr;i++)
6957 if (values1[i] != NULL)
6958 xmlFree(values1[i]);
6959 for (j = 0;j < ns2->nodeNr;j++)
6960 if (values2[j] != NULL)
6961 xmlFree(values2[j]);
6962 xmlFree(values1);
6963 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006964 xmlFree(hashs1);
6965 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006966 return(ret);
6967}
6968
William M. Brack0c022ad2002-07-12 00:56:01 +00006969static int
6970xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6971 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006972 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006973 /*
6974 *At this point we are assured neither arg1 nor arg2
6975 *is a nodeset, so we can just pick the appropriate routine.
6976 */
Owen Taylor3473f882001-02-23 17:55:21 +00006977 switch (arg1->type) {
6978 case XPATH_UNDEFINED:
6979#ifdef DEBUG_EXPR
6980 xmlGenericError(xmlGenericErrorContext,
6981 "Equal: undefined\n");
6982#endif
6983 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006984 case XPATH_BOOLEAN:
6985 switch (arg2->type) {
6986 case XPATH_UNDEFINED:
6987#ifdef DEBUG_EXPR
6988 xmlGenericError(xmlGenericErrorContext,
6989 "Equal: undefined\n");
6990#endif
6991 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006992 case XPATH_BOOLEAN:
6993#ifdef DEBUG_EXPR
6994 xmlGenericError(xmlGenericErrorContext,
6995 "Equal: %d boolean %d \n",
6996 arg1->boolval, arg2->boolval);
6997#endif
6998 ret = (arg1->boolval == arg2->boolval);
6999 break;
7000 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00007001 ret = (arg1->boolval ==
7002 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007003 break;
7004 case XPATH_STRING:
7005 if ((arg2->stringval == NULL) ||
7006 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007007 else
Owen Taylor3473f882001-02-23 17:55:21 +00007008 ret = 1;
7009 ret = (arg1->boolval == ret);
7010 break;
7011 case XPATH_USERS:
7012 case XPATH_POINT:
7013 case XPATH_RANGE:
7014 case XPATH_LOCATIONSET:
7015 TODO
7016 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007017 case XPATH_NODESET:
7018 case XPATH_XSLT_TREE:
7019 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007020 }
7021 break;
7022 case XPATH_NUMBER:
7023 switch (arg2->type) {
7024 case XPATH_UNDEFINED:
7025#ifdef DEBUG_EXPR
7026 xmlGenericError(xmlGenericErrorContext,
7027 "Equal: undefined\n");
7028#endif
7029 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007030 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00007031 ret = (arg2->boolval==
7032 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007033 break;
7034 case XPATH_STRING:
7035 valuePush(ctxt, arg2);
7036 xmlXPathNumberFunction(ctxt, 1);
7037 arg2 = valuePop(ctxt);
J. Peter Mugaasd2c329a2017-10-21 13:49:31 +02007038 /* Falls through. */
Owen Taylor3473f882001-02-23 17:55:21 +00007039 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007040 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007041 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007042 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007043 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007044 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7045 if (xmlXPathIsInf(arg2->floatval) == 1)
7046 ret = 1;
7047 else
7048 ret = 0;
7049 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7050 if (xmlXPathIsInf(arg2->floatval) == -1)
7051 ret = 1;
7052 else
7053 ret = 0;
7054 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7055 if (xmlXPathIsInf(arg1->floatval) == 1)
7056 ret = 1;
7057 else
7058 ret = 0;
7059 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7060 if (xmlXPathIsInf(arg1->floatval) == -1)
7061 ret = 1;
7062 else
7063 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007064 } else {
7065 ret = (arg1->floatval == arg2->floatval);
7066 }
Owen Taylor3473f882001-02-23 17:55:21 +00007067 break;
7068 case XPATH_USERS:
7069 case XPATH_POINT:
7070 case XPATH_RANGE:
7071 case XPATH_LOCATIONSET:
7072 TODO
7073 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007074 case XPATH_NODESET:
7075 case XPATH_XSLT_TREE:
7076 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007077 }
7078 break;
7079 case XPATH_STRING:
7080 switch (arg2->type) {
7081 case XPATH_UNDEFINED:
7082#ifdef DEBUG_EXPR
7083 xmlGenericError(xmlGenericErrorContext,
7084 "Equal: undefined\n");
7085#endif
7086 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007087 case XPATH_BOOLEAN:
7088 if ((arg1->stringval == NULL) ||
7089 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007090 else
Owen Taylor3473f882001-02-23 17:55:21 +00007091 ret = 1;
7092 ret = (arg2->boolval == ret);
7093 break;
7094 case XPATH_STRING:
7095 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7096 break;
7097 case XPATH_NUMBER:
7098 valuePush(ctxt, arg1);
7099 xmlXPathNumberFunction(ctxt, 1);
7100 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007101 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007102 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007103 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007104 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007105 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7106 if (xmlXPathIsInf(arg2->floatval) == 1)
7107 ret = 1;
7108 else
7109 ret = 0;
7110 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7111 if (xmlXPathIsInf(arg2->floatval) == -1)
7112 ret = 1;
7113 else
7114 ret = 0;
7115 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7116 if (xmlXPathIsInf(arg1->floatval) == 1)
7117 ret = 1;
7118 else
7119 ret = 0;
7120 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7121 if (xmlXPathIsInf(arg1->floatval) == -1)
7122 ret = 1;
7123 else
7124 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007125 } else {
7126 ret = (arg1->floatval == arg2->floatval);
7127 }
Owen Taylor3473f882001-02-23 17:55:21 +00007128 break;
7129 case XPATH_USERS:
7130 case XPATH_POINT:
7131 case XPATH_RANGE:
7132 case XPATH_LOCATIONSET:
7133 TODO
7134 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007135 case XPATH_NODESET:
7136 case XPATH_XSLT_TREE:
7137 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007138 }
7139 break;
7140 case XPATH_USERS:
7141 case XPATH_POINT:
7142 case XPATH_RANGE:
7143 case XPATH_LOCATIONSET:
7144 TODO
7145 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007146 case XPATH_NODESET:
7147 case XPATH_XSLT_TREE:
7148 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007149 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007150 xmlXPathReleaseObject(ctxt->context, arg1);
7151 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007152 return(ret);
7153}
7154
William M. Brack0c022ad2002-07-12 00:56:01 +00007155/**
7156 * xmlXPathEqualValues:
7157 * @ctxt: the XPath Parser context
7158 *
7159 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7160 *
7161 * Returns 0 or 1 depending on the results of the test.
7162 */
7163int
7164xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7165 xmlXPathObjectPtr arg1, arg2, argtmp;
7166 int ret = 0;
7167
Daniel Veillard6128c012004-11-08 17:16:15 +00007168 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007169 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007170 arg1 = valuePop(ctxt);
7171 if ((arg1 == NULL) || (arg2 == NULL)) {
7172 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007173 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007174 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007175 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007176 XP_ERROR0(XPATH_INVALID_OPERAND);
7177 }
7178
7179 if (arg1 == arg2) {
7180#ifdef DEBUG_EXPR
7181 xmlGenericError(xmlGenericErrorContext,
7182 "Equal: by pointer\n");
7183#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007184 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007185 return(1);
7186 }
7187
7188 /*
7189 *If either argument is a nodeset, it's a 'special case'
7190 */
7191 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7192 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7193 /*
7194 *Hack it to assure arg1 is the nodeset
7195 */
7196 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7197 argtmp = arg2;
7198 arg2 = arg1;
7199 arg1 = argtmp;
7200 }
7201 switch (arg2->type) {
7202 case XPATH_UNDEFINED:
7203#ifdef DEBUG_EXPR
7204 xmlGenericError(xmlGenericErrorContext,
7205 "Equal: undefined\n");
7206#endif
7207 break;
7208 case XPATH_NODESET:
7209 case XPATH_XSLT_TREE:
7210 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7211 break;
7212 case XPATH_BOOLEAN:
7213 if ((arg1->nodesetval == NULL) ||
7214 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007215 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007216 ret = 1;
7217 ret = (ret == arg2->boolval);
7218 break;
7219 case XPATH_NUMBER:
7220 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7221 break;
7222 case XPATH_STRING:
7223 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7224 break;
7225 case XPATH_USERS:
7226 case XPATH_POINT:
7227 case XPATH_RANGE:
7228 case XPATH_LOCATIONSET:
7229 TODO
7230 break;
7231 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007232 xmlXPathReleaseObject(ctxt->context, arg1);
7233 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007234 return(ret);
7235 }
7236
7237 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7238}
7239
7240/**
7241 * xmlXPathNotEqualValues:
7242 * @ctxt: the XPath Parser context
7243 *
7244 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7245 *
7246 * Returns 0 or 1 depending on the results of the test.
7247 */
7248int
7249xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7250 xmlXPathObjectPtr arg1, arg2, argtmp;
7251 int ret = 0;
7252
Daniel Veillard6128c012004-11-08 17:16:15 +00007253 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007254 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007255 arg1 = valuePop(ctxt);
7256 if ((arg1 == NULL) || (arg2 == NULL)) {
7257 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007258 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007259 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007260 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007261 XP_ERROR0(XPATH_INVALID_OPERAND);
7262 }
7263
7264 if (arg1 == arg2) {
7265#ifdef DEBUG_EXPR
7266 xmlGenericError(xmlGenericErrorContext,
7267 "NotEqual: by pointer\n");
7268#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007269 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007270 return(0);
7271 }
7272
7273 /*
7274 *If either argument is a nodeset, it's a 'special case'
7275 */
7276 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7277 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7278 /*
7279 *Hack it to assure arg1 is the nodeset
7280 */
7281 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7282 argtmp = arg2;
7283 arg2 = arg1;
7284 arg1 = argtmp;
7285 }
7286 switch (arg2->type) {
7287 case XPATH_UNDEFINED:
7288#ifdef DEBUG_EXPR
7289 xmlGenericError(xmlGenericErrorContext,
7290 "NotEqual: undefined\n");
7291#endif
7292 break;
7293 case XPATH_NODESET:
7294 case XPATH_XSLT_TREE:
7295 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7296 break;
7297 case XPATH_BOOLEAN:
7298 if ((arg1->nodesetval == NULL) ||
7299 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007300 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007301 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007302 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007303 break;
7304 case XPATH_NUMBER:
7305 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7306 break;
7307 case XPATH_STRING:
7308 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7309 break;
7310 case XPATH_USERS:
7311 case XPATH_POINT:
7312 case XPATH_RANGE:
7313 case XPATH_LOCATIONSET:
7314 TODO
7315 break;
7316 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007317 xmlXPathReleaseObject(ctxt->context, arg1);
7318 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007319 return(ret);
7320 }
7321
7322 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7323}
Owen Taylor3473f882001-02-23 17:55:21 +00007324
7325/**
7326 * xmlXPathCompareValues:
7327 * @ctxt: the XPath Parser context
7328 * @inf: less than (1) or greater than (0)
7329 * @strict: is the comparison strict
7330 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007331 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007332 * @arg1 < @arg2 (1, 1, ...
7333 * @arg1 <= @arg2 (1, 0, ...
7334 * @arg1 > @arg2 (0, 1, ...
7335 * @arg1 >= @arg2 (0, 0, ...
7336 *
7337 * When neither object to be compared is a node-set and the operator is
7338 * <=, <, >=, >, then the objects are compared by converted both objects
7339 * to numbers and comparing the numbers according to IEEE 754. The <
7340 * comparison will be true if and only if the first number is less than the
7341 * second number. The <= comparison will be true if and only if the first
7342 * number is less than or equal to the second number. The > comparison
7343 * will be true if and only if the first number is greater than the second
7344 * number. The >= comparison will be true if and only if the first number
7345 * is greater than or equal to the second number.
7346 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007347 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007348 */
7349int
7350xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007351 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007352 xmlXPathObjectPtr arg1, arg2;
7353
Daniel Veillard6128c012004-11-08 17:16:15 +00007354 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007355 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007356 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007357 if ((arg1 == NULL) || (arg2 == NULL)) {
7358 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007359 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007360 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007361 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007362 XP_ERROR0(XPATH_INVALID_OPERAND);
7363 }
7364
William M. Brack0c022ad2002-07-12 00:56:01 +00007365 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7366 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007367 /*
7368 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7369 * are not freed from within this routine; they will be freed from the
7370 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
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))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007374 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007375 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007376 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007377 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7378 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007379 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007380 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7381 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007382 }
7383 }
7384 return(ret);
7385 }
7386
7387 if (arg1->type != XPATH_NUMBER) {
7388 valuePush(ctxt, arg1);
7389 xmlXPathNumberFunction(ctxt, 1);
7390 arg1 = valuePop(ctxt);
7391 }
7392 if (arg1->type != XPATH_NUMBER) {
7393 xmlXPathFreeObject(arg1);
7394 xmlXPathFreeObject(arg2);
7395 XP_ERROR0(XPATH_INVALID_OPERAND);
7396 }
7397 if (arg2->type != XPATH_NUMBER) {
7398 valuePush(ctxt, arg2);
7399 xmlXPathNumberFunction(ctxt, 1);
7400 arg2 = valuePop(ctxt);
7401 }
7402 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007403 xmlXPathReleaseObject(ctxt->context, arg1);
7404 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007405 XP_ERROR0(XPATH_INVALID_OPERAND);
7406 }
7407 /*
7408 * Add tests for infinity and nan
7409 * => feedback on 3.4 for Inf and NaN
7410 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007411 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007412 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007413 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007414 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007415 arg1i=xmlXPathIsInf(arg1->floatval);
7416 arg2i=xmlXPathIsInf(arg2->floatval);
7417 if (inf && strict) {
7418 if ((arg1i == -1 && arg2i != -1) ||
7419 (arg2i == 1 && arg1i != 1)) {
7420 ret = 1;
7421 } else if (arg1i == 0 && arg2i == 0) {
7422 ret = (arg1->floatval < arg2->floatval);
7423 } else {
7424 ret = 0;
7425 }
7426 }
7427 else if (inf && !strict) {
7428 if (arg1i == -1 || arg2i == 1) {
7429 ret = 1;
7430 } else if (arg1i == 0 && arg2i == 0) {
7431 ret = (arg1->floatval <= arg2->floatval);
7432 } else {
7433 ret = 0;
7434 }
7435 }
7436 else if (!inf && strict) {
7437 if ((arg1i == 1 && arg2i != 1) ||
7438 (arg2i == -1 && arg1i != -1)) {
7439 ret = 1;
7440 } else if (arg1i == 0 && arg2i == 0) {
7441 ret = (arg1->floatval > arg2->floatval);
7442 } else {
7443 ret = 0;
7444 }
7445 }
7446 else if (!inf && !strict) {
7447 if (arg1i == 1 || arg2i == -1) {
7448 ret = 1;
7449 } else if (arg1i == 0 && arg2i == 0) {
7450 ret = (arg1->floatval >= arg2->floatval);
7451 } else {
7452 ret = 0;
7453 }
7454 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007455 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007456 xmlXPathReleaseObject(ctxt->context, arg1);
7457 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007458 return(ret);
7459}
7460
7461/**
7462 * xmlXPathValueFlipSign:
7463 * @ctxt: the XPath Parser context
7464 *
7465 * Implement the unary - operation on an XPath object
7466 * The numeric operators convert their operands to numbers as if
7467 * by calling the number function.
7468 */
7469void
7470xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007471 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007472 CAST_TO_NUMBER;
7473 CHECK_TYPE(XPATH_NUMBER);
Nick Wellnhofer8813f392017-09-21 00:11:26 +02007474 ctxt->value->floatval = -ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007475}
7476
7477/**
7478 * xmlXPathAddValues:
7479 * @ctxt: the XPath Parser context
7480 *
7481 * Implement the add operation on XPath objects:
7482 * The numeric operators convert their operands to numbers as if
7483 * by calling the number function.
7484 */
7485void
7486xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7487 xmlXPathObjectPtr arg;
7488 double val;
7489
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007490 arg = valuePop(ctxt);
7491 if (arg == NULL)
7492 XP_ERROR(XPATH_INVALID_OPERAND);
7493 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007494 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007495 CAST_TO_NUMBER;
7496 CHECK_TYPE(XPATH_NUMBER);
7497 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007498}
7499
7500/**
7501 * xmlXPathSubValues:
7502 * @ctxt: the XPath Parser context
7503 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007504 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007505 * The numeric operators convert their operands to numbers as if
7506 * by calling the number function.
7507 */
7508void
7509xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7510 xmlXPathObjectPtr arg;
7511 double val;
7512
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007513 arg = valuePop(ctxt);
7514 if (arg == NULL)
7515 XP_ERROR(XPATH_INVALID_OPERAND);
7516 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007517 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007518 CAST_TO_NUMBER;
7519 CHECK_TYPE(XPATH_NUMBER);
7520 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007521}
7522
7523/**
7524 * xmlXPathMultValues:
7525 * @ctxt: the XPath Parser context
7526 *
7527 * Implement the multiply operation on XPath objects:
7528 * The numeric operators convert their operands to numbers as if
7529 * by calling the number function.
7530 */
7531void
7532xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7533 xmlXPathObjectPtr arg;
7534 double val;
7535
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007536 arg = valuePop(ctxt);
7537 if (arg == NULL)
7538 XP_ERROR(XPATH_INVALID_OPERAND);
7539 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007540 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007541 CAST_TO_NUMBER;
7542 CHECK_TYPE(XPATH_NUMBER);
7543 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007544}
7545
7546/**
7547 * xmlXPathDivValues:
7548 * @ctxt: the XPath Parser context
7549 *
7550 * Implement the div operation on XPath objects @arg1 / @arg2:
7551 * The numeric operators convert their operands to numbers as if
7552 * by calling the number function.
7553 */
7554void
7555xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7556 xmlXPathObjectPtr arg;
7557 double val;
7558
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007559 arg = valuePop(ctxt);
7560 if (arg == NULL)
7561 XP_ERROR(XPATH_INVALID_OPERAND);
7562 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007563 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007564 CAST_TO_NUMBER;
7565 CHECK_TYPE(XPATH_NUMBER);
Nick Wellnhofer8813f392017-09-21 00:11:26 +02007566 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007567}
7568
7569/**
7570 * xmlXPathModValues:
7571 * @ctxt: the XPath Parser context
7572 *
7573 * Implement the mod operation on XPath objects: @arg1 / @arg2
7574 * The numeric operators convert their operands to numbers as if
7575 * by calling the number function.
7576 */
7577void
7578xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7579 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007580 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007581
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007582 arg = valuePop(ctxt);
7583 if (arg == NULL)
7584 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007585 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007586 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007587 CAST_TO_NUMBER;
7588 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007589 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007590 if (arg2 == 0)
Nick Wellnhofer8813f392017-09-21 00:11:26 +02007591 ctxt->value->floatval = NAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007592 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007593 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007594 }
Owen Taylor3473f882001-02-23 17:55:21 +00007595}
7596
7597/************************************************************************
7598 * *
7599 * The traversal functions *
7600 * *
7601 ************************************************************************/
7602
Owen Taylor3473f882001-02-23 17:55:21 +00007603/*
7604 * A traversal function enumerates nodes along an axis.
7605 * Initially it must be called with NULL, and it indicates
7606 * termination on the axis by returning NULL.
7607 */
7608typedef xmlNodePtr (*xmlXPathTraversalFunction)
7609 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7610
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007611/*
7612 * xmlXPathTraversalFunctionExt:
7613 * A traversal function enumerates nodes along an axis.
7614 * Initially it must be called with NULL, and it indicates
7615 * termination on the axis by returning NULL.
7616 * The context node of the traversal is specified via @contextNode.
7617 */
7618typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7619 (xmlNodePtr cur, xmlNodePtr contextNode);
7620
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007621/*
7622 * xmlXPathNodeSetMergeFunction:
7623 * Used for merging node sets in xmlXPathCollectAndTest().
7624 */
7625typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7626 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7627
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007628
Owen Taylor3473f882001-02-23 17:55:21 +00007629/**
7630 * xmlXPathNextSelf:
7631 * @ctxt: the XPath Parser context
7632 * @cur: the current node in the traversal
7633 *
7634 * Traversal function for the "self" direction
7635 * The self axis contains just the context node itself
7636 *
7637 * Returns the next element following that axis
7638 */
7639xmlNodePtr
7640xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007641 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007642 if (cur == NULL)
7643 return(ctxt->context->node);
7644 return(NULL);
7645}
7646
7647/**
7648 * xmlXPathNextChild:
7649 * @ctxt: the XPath Parser context
7650 * @cur: the current node in the traversal
7651 *
7652 * Traversal function for the "child" direction
7653 * The child axis contains the children of the context node in document order.
7654 *
7655 * Returns the next element following that axis
7656 */
7657xmlNodePtr
7658xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007659 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007660 if (cur == NULL) {
7661 if (ctxt->context->node == NULL) return(NULL);
7662 switch (ctxt->context->node->type) {
7663 case XML_ELEMENT_NODE:
7664 case XML_TEXT_NODE:
7665 case XML_CDATA_SECTION_NODE:
7666 case XML_ENTITY_REF_NODE:
7667 case XML_ENTITY_NODE:
7668 case XML_PI_NODE:
7669 case XML_COMMENT_NODE:
7670 case XML_NOTATION_NODE:
7671 case XML_DTD_NODE:
7672 return(ctxt->context->node->children);
7673 case XML_DOCUMENT_NODE:
7674 case XML_DOCUMENT_TYPE_NODE:
7675 case XML_DOCUMENT_FRAG_NODE:
7676 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007677#ifdef LIBXML_DOCB_ENABLED
7678 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007679#endif
7680 return(((xmlDocPtr) ctxt->context->node)->children);
7681 case XML_ELEMENT_DECL:
7682 case XML_ATTRIBUTE_DECL:
7683 case XML_ENTITY_DECL:
7684 case XML_ATTRIBUTE_NODE:
7685 case XML_NAMESPACE_DECL:
7686 case XML_XINCLUDE_START:
7687 case XML_XINCLUDE_END:
7688 return(NULL);
7689 }
7690 return(NULL);
7691 }
7692 if ((cur->type == XML_DOCUMENT_NODE) ||
7693 (cur->type == XML_HTML_DOCUMENT_NODE))
7694 return(NULL);
7695 return(cur->next);
7696}
7697
7698/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007699 * xmlXPathNextChildElement:
7700 * @ctxt: the XPath Parser context
7701 * @cur: the current node in the traversal
7702 *
7703 * Traversal function for the "child" direction and nodes of type element.
7704 * The child axis contains the children of the context node in document order.
7705 *
7706 * Returns the next element following that axis
7707 */
7708static xmlNodePtr
7709xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7710 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7711 if (cur == NULL) {
7712 cur = ctxt->context->node;
7713 if (cur == NULL) return(NULL);
7714 /*
7715 * Get the first element child.
7716 */
7717 switch (cur->type) {
7718 case XML_ELEMENT_NODE:
7719 case XML_DOCUMENT_FRAG_NODE:
7720 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7721 case XML_ENTITY_NODE:
7722 cur = cur->children;
7723 if (cur != NULL) {
7724 if (cur->type == XML_ELEMENT_NODE)
7725 return(cur);
7726 do {
7727 cur = cur->next;
7728 } while ((cur != NULL) &&
7729 (cur->type != XML_ELEMENT_NODE));
7730 return(cur);
7731 }
7732 return(NULL);
7733 case XML_DOCUMENT_NODE:
7734 case XML_HTML_DOCUMENT_NODE:
7735#ifdef LIBXML_DOCB_ENABLED
7736 case XML_DOCB_DOCUMENT_NODE:
7737#endif
7738 return(xmlDocGetRootElement((xmlDocPtr) cur));
7739 default:
7740 return(NULL);
7741 }
7742 return(NULL);
7743 }
7744 /*
7745 * Get the next sibling element node.
7746 */
7747 switch (cur->type) {
7748 case XML_ELEMENT_NODE:
7749 case XML_TEXT_NODE:
7750 case XML_ENTITY_REF_NODE:
7751 case XML_ENTITY_NODE:
7752 case XML_CDATA_SECTION_NODE:
7753 case XML_PI_NODE:
7754 case XML_COMMENT_NODE:
7755 case XML_XINCLUDE_END:
7756 break;
7757 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7758 default:
7759 return(NULL);
7760 }
7761 if (cur->next != NULL) {
7762 if (cur->next->type == XML_ELEMENT_NODE)
7763 return(cur->next);
7764 cur = cur->next;
7765 do {
7766 cur = cur->next;
7767 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7768 return(cur);
7769 }
7770 return(NULL);
7771}
7772
Daniel Veillard76516062012-09-11 14:02:08 +08007773#if 0
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007774/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007775 * xmlXPathNextDescendantOrSelfElemParent:
7776 * @ctxt: the XPath Parser context
7777 * @cur: the current node in the traversal
7778 *
7779 * Traversal function for the "descendant-or-self" axis.
7780 * Additionally it returns only nodes which can be parents of
7781 * element nodes.
7782 *
7783 *
7784 * Returns the next element following that axis
7785 */
7786static xmlNodePtr
7787xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7788 xmlNodePtr contextNode)
7789{
7790 if (cur == NULL) {
7791 if (contextNode == NULL)
7792 return(NULL);
7793 switch (contextNode->type) {
7794 case XML_ELEMENT_NODE:
7795 case XML_XINCLUDE_START:
7796 case XML_DOCUMENT_FRAG_NODE:
7797 case XML_DOCUMENT_NODE:
7798#ifdef LIBXML_DOCB_ENABLED
7799 case XML_DOCB_DOCUMENT_NODE:
7800#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007801 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007802 return(contextNode);
7803 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007804 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007805 }
7806 return(NULL);
7807 } else {
7808 xmlNodePtr start = cur;
7809
7810 while (cur != NULL) {
7811 switch (cur->type) {
7812 case XML_ELEMENT_NODE:
7813 /* TODO: OK to have XInclude here? */
7814 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007815 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007816 if (cur != start)
7817 return(cur);
7818 if (cur->children != NULL) {
7819 cur = cur->children;
7820 continue;
7821 }
7822 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007823 /* Not sure if we need those here. */
7824 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007825#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007826 case XML_DOCB_DOCUMENT_NODE:
7827#endif
7828 case XML_HTML_DOCUMENT_NODE:
7829 if (cur != start)
7830 return(cur);
7831 return(xmlDocGetRootElement((xmlDocPtr) cur));
7832 default:
7833 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007834 }
7835
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007836next_sibling:
7837 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007838 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007839 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007840 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007841 } else {
7842 cur = cur->parent;
7843 goto next_sibling;
7844 }
7845 }
7846 }
7847 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007848}
Daniel Veillard76516062012-09-11 14:02:08 +08007849#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007850
7851/**
Owen Taylor3473f882001-02-23 17:55:21 +00007852 * xmlXPathNextDescendant:
7853 * @ctxt: the XPath Parser context
7854 * @cur: the current node in the traversal
7855 *
7856 * Traversal function for the "descendant" direction
7857 * the descendant axis contains the descendants of the context node in document
7858 * order; a descendant is a child or a child of a child and so on.
7859 *
7860 * Returns the next element following that axis
7861 */
7862xmlNodePtr
7863xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007864 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007865 if (cur == NULL) {
7866 if (ctxt->context->node == NULL)
7867 return(NULL);
7868 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7869 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7870 return(NULL);
7871
7872 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7873 return(ctxt->context->doc->children);
7874 return(ctxt->context->node->children);
7875 }
7876
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007877 if (cur->type == XML_NAMESPACE_DECL)
7878 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007879 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007880 /*
7881 * Do not descend on entities declarations
7882 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007883 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007884 cur = cur->children;
7885 /*
7886 * Skip DTDs
7887 */
7888 if (cur->type != XML_DTD_NODE)
7889 return(cur);
7890 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007891 }
7892
7893 if (cur == ctxt->context->node) return(NULL);
7894
Daniel Veillard68e9e742002-11-16 15:35:11 +00007895 while (cur->next != NULL) {
7896 cur = cur->next;
7897 if ((cur->type != XML_ENTITY_DECL) &&
7898 (cur->type != XML_DTD_NODE))
7899 return(cur);
7900 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007901
Owen Taylor3473f882001-02-23 17:55:21 +00007902 do {
7903 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007904 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007905 if (cur == ctxt->context->node) return(NULL);
7906 if (cur->next != NULL) {
7907 cur = cur->next;
7908 return(cur);
7909 }
7910 } while (cur != NULL);
7911 return(cur);
7912}
7913
7914/**
7915 * xmlXPathNextDescendantOrSelf:
7916 * @ctxt: the XPath Parser context
7917 * @cur: the current node in the traversal
7918 *
7919 * Traversal function for the "descendant-or-self" direction
7920 * the descendant-or-self axis contains the context node and the descendants
7921 * of the context node in document order; thus the context node is the first
7922 * node on the axis, and the first child of the context node is the second node
7923 * on the axis
7924 *
7925 * Returns the next element following that axis
7926 */
7927xmlNodePtr
7928xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007929 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007930 if (cur == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007931 return(ctxt->context->node);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007932
7933 if (ctxt->context->node == NULL)
7934 return(NULL);
7935 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7936 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7937 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007938
7939 return(xmlXPathNextDescendant(ctxt, cur));
7940}
7941
7942/**
7943 * xmlXPathNextParent:
7944 * @ctxt: the XPath Parser context
7945 * @cur: the current node in the traversal
7946 *
7947 * Traversal function for the "parent" direction
7948 * The parent axis contains the parent of the context node, if there is one.
7949 *
7950 * Returns the next element following that axis
7951 */
7952xmlNodePtr
7953xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007954 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007955 /*
7956 * the parent of an attribute or namespace node is the element
7957 * to which the attribute or namespace node is attached
7958 * Namespace handling !!!
7959 */
7960 if (cur == NULL) {
7961 if (ctxt->context->node == NULL) return(NULL);
7962 switch (ctxt->context->node->type) {
7963 case XML_ELEMENT_NODE:
7964 case XML_TEXT_NODE:
7965 case XML_CDATA_SECTION_NODE:
7966 case XML_ENTITY_REF_NODE:
7967 case XML_ENTITY_NODE:
7968 case XML_PI_NODE:
7969 case XML_COMMENT_NODE:
7970 case XML_NOTATION_NODE:
7971 case XML_DTD_NODE:
7972 case XML_ELEMENT_DECL:
7973 case XML_ATTRIBUTE_DECL:
7974 case XML_XINCLUDE_START:
7975 case XML_XINCLUDE_END:
7976 case XML_ENTITY_DECL:
7977 if (ctxt->context->node->parent == NULL)
7978 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007979 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007980 ((ctxt->context->node->parent->name[0] == ' ') ||
7981 (xmlStrEqual(ctxt->context->node->parent->name,
7982 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007983 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007984 return(ctxt->context->node->parent);
7985 case XML_ATTRIBUTE_NODE: {
7986 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7987
7988 return(att->parent);
7989 }
7990 case XML_DOCUMENT_NODE:
7991 case XML_DOCUMENT_TYPE_NODE:
7992 case XML_DOCUMENT_FRAG_NODE:
7993 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007994#ifdef LIBXML_DOCB_ENABLED
7995 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007996#endif
7997 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007998 case XML_NAMESPACE_DECL: {
7999 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008000
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008001 if ((ns->next != NULL) &&
8002 (ns->next->type != XML_NAMESPACE_DECL))
8003 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00008004 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008005 }
Owen Taylor3473f882001-02-23 17:55:21 +00008006 }
8007 }
8008 return(NULL);
8009}
8010
8011/**
8012 * xmlXPathNextAncestor:
8013 * @ctxt: the XPath Parser context
8014 * @cur: the current node in the traversal
8015 *
8016 * Traversal function for the "ancestor" direction
8017 * the ancestor axis contains the ancestors of the context node; the ancestors
8018 * of the context node consist of the parent of context node and the parent's
8019 * parent and so on; the nodes are ordered in reverse document order; thus the
8020 * parent is the first node on the axis, and the parent's parent is the second
8021 * node on the axis
8022 *
8023 * Returns the next element following that axis
8024 */
8025xmlNodePtr
8026xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008027 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008028 /*
8029 * the parent of an attribute or namespace node is the element
8030 * to which the attribute or namespace node is attached
8031 * !!!!!!!!!!!!!
8032 */
8033 if (cur == NULL) {
8034 if (ctxt->context->node == NULL) return(NULL);
8035 switch (ctxt->context->node->type) {
8036 case XML_ELEMENT_NODE:
8037 case XML_TEXT_NODE:
8038 case XML_CDATA_SECTION_NODE:
8039 case XML_ENTITY_REF_NODE:
8040 case XML_ENTITY_NODE:
8041 case XML_PI_NODE:
8042 case XML_COMMENT_NODE:
8043 case XML_DTD_NODE:
8044 case XML_ELEMENT_DECL:
8045 case XML_ATTRIBUTE_DECL:
8046 case XML_ENTITY_DECL:
8047 case XML_NOTATION_NODE:
8048 case XML_XINCLUDE_START:
8049 case XML_XINCLUDE_END:
8050 if (ctxt->context->node->parent == NULL)
8051 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008052 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008053 ((ctxt->context->node->parent->name[0] == ' ') ||
8054 (xmlStrEqual(ctxt->context->node->parent->name,
8055 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008056 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008057 return(ctxt->context->node->parent);
8058 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008059 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00008060
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008061 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00008062 }
8063 case XML_DOCUMENT_NODE:
8064 case XML_DOCUMENT_TYPE_NODE:
8065 case XML_DOCUMENT_FRAG_NODE:
8066 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008067#ifdef LIBXML_DOCB_ENABLED
8068 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008069#endif
8070 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008071 case XML_NAMESPACE_DECL: {
8072 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008073
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008074 if ((ns->next != NULL) &&
8075 (ns->next->type != XML_NAMESPACE_DECL))
8076 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008077 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008078 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008079 }
Owen Taylor3473f882001-02-23 17:55:21 +00008080 }
8081 return(NULL);
8082 }
8083 if (cur == ctxt->context->doc->children)
8084 return((xmlNodePtr) ctxt->context->doc);
8085 if (cur == (xmlNodePtr) ctxt->context->doc)
8086 return(NULL);
8087 switch (cur->type) {
8088 case XML_ELEMENT_NODE:
8089 case XML_TEXT_NODE:
8090 case XML_CDATA_SECTION_NODE:
8091 case XML_ENTITY_REF_NODE:
8092 case XML_ENTITY_NODE:
8093 case XML_PI_NODE:
8094 case XML_COMMENT_NODE:
8095 case XML_NOTATION_NODE:
8096 case XML_DTD_NODE:
8097 case XML_ELEMENT_DECL:
8098 case XML_ATTRIBUTE_DECL:
8099 case XML_ENTITY_DECL:
8100 case XML_XINCLUDE_START:
8101 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008102 if (cur->parent == NULL)
8103 return(NULL);
8104 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008105 ((cur->parent->name[0] == ' ') ||
8106 (xmlStrEqual(cur->parent->name,
8107 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008108 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008109 return(cur->parent);
8110 case XML_ATTRIBUTE_NODE: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008111 xmlAttrPtr att = (xmlAttrPtr) cur;
Owen Taylor3473f882001-02-23 17:55:21 +00008112
8113 return(att->parent);
8114 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008115 case XML_NAMESPACE_DECL: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008116 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008117
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008118 if ((ns->next != NULL) &&
8119 (ns->next->type != XML_NAMESPACE_DECL))
8120 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008121 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008122 return(NULL);
8123 }
Owen Taylor3473f882001-02-23 17:55:21 +00008124 case XML_DOCUMENT_NODE:
8125 case XML_DOCUMENT_TYPE_NODE:
8126 case XML_DOCUMENT_FRAG_NODE:
8127 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008128#ifdef LIBXML_DOCB_ENABLED
8129 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008130#endif
8131 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008132 }
8133 return(NULL);
8134}
8135
8136/**
8137 * xmlXPathNextAncestorOrSelf:
8138 * @ctxt: the XPath Parser context
8139 * @cur: the current node in the traversal
8140 *
8141 * Traversal function for the "ancestor-or-self" direction
8142 * he ancestor-or-self axis contains the context node and ancestors of
8143 * the context node in reverse document order; thus the context node is
8144 * the first node on the axis, and the context node's parent the second;
8145 * parent here is defined the same as with the parent axis.
8146 *
8147 * Returns the next element following that axis
8148 */
8149xmlNodePtr
8150xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008151 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008152 if (cur == NULL)
8153 return(ctxt->context->node);
8154 return(xmlXPathNextAncestor(ctxt, cur));
8155}
8156
8157/**
8158 * xmlXPathNextFollowingSibling:
8159 * @ctxt: the XPath Parser context
8160 * @cur: the current node in the traversal
8161 *
8162 * Traversal function for the "following-sibling" direction
8163 * The following-sibling axis contains the following siblings of the context
8164 * node in document order.
8165 *
8166 * Returns the next element following that axis
8167 */
8168xmlNodePtr
8169xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008170 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008171 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8172 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8173 return(NULL);
8174 if (cur == (xmlNodePtr) ctxt->context->doc)
8175 return(NULL);
8176 if (cur == NULL)
8177 return(ctxt->context->node->next);
8178 return(cur->next);
8179}
8180
8181/**
8182 * xmlXPathNextPrecedingSibling:
8183 * @ctxt: the XPath Parser context
8184 * @cur: the current node in the traversal
8185 *
8186 * Traversal function for the "preceding-sibling" direction
8187 * The preceding-sibling axis contains the preceding siblings of the context
8188 * node in reverse document order; the first preceding sibling is first on the
8189 * axis; the sibling preceding that node is the second on the axis and so on.
8190 *
8191 * Returns the next element following that axis
8192 */
8193xmlNodePtr
8194xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008195 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008196 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8197 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8198 return(NULL);
8199 if (cur == (xmlNodePtr) ctxt->context->doc)
8200 return(NULL);
8201 if (cur == NULL)
8202 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008203 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8204 cur = cur->prev;
8205 if (cur == NULL)
8206 return(ctxt->context->node->prev);
8207 }
Owen Taylor3473f882001-02-23 17:55:21 +00008208 return(cur->prev);
8209}
8210
8211/**
8212 * xmlXPathNextFollowing:
8213 * @ctxt: the XPath Parser context
8214 * @cur: the current node in the traversal
8215 *
8216 * Traversal function for the "following" direction
8217 * The following axis contains all nodes in the same document as the context
8218 * node that are after the context node in document order, excluding any
8219 * descendants and excluding attribute nodes and namespace nodes; the nodes
8220 * are ordered in document order
8221 *
8222 * Returns the next element following that axis
8223 */
8224xmlNodePtr
8225xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008226 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008227 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8228 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8229 return(cur->children);
8230
8231 if (cur == NULL) {
8232 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008233 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardea90b892010-10-22 15:50:50 +02008234 cur = cur->parent;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008235 } else if (cur->type == XML_NAMESPACE_DECL) {
8236 xmlNsPtr ns = (xmlNsPtr) cur;
8237
8238 if ((ns->next == NULL) ||
8239 (ns->next->type == XML_NAMESPACE_DECL))
8240 return (NULL);
8241 cur = (xmlNodePtr) ns->next;
8242 }
Daniel Veillard91d19752010-10-15 14:30:52 +02008243 }
Owen Taylor3473f882001-02-23 17:55:21 +00008244 if (cur == NULL) return(NULL) ; /* ERROR */
8245 if (cur->next != NULL) return(cur->next) ;
8246 do {
8247 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008248 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008249 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8250 if (cur->next != NULL) return(cur->next);
8251 } while (cur != NULL);
8252 return(cur);
8253}
8254
8255/*
8256 * xmlXPathIsAncestor:
8257 * @ancestor: the ancestor node
8258 * @node: the current node
8259 *
8260 * Check that @ancestor is a @node's ancestor
8261 *
8262 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8263 */
8264static int
8265xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8266 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008267 if (node->type == XML_NAMESPACE_DECL)
8268 return(0);
8269 if (ancestor->type == XML_NAMESPACE_DECL)
8270 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008271 /* nodes need to be in the same document */
8272 if (ancestor->doc != node->doc) return(0);
8273 /* avoid searching if ancestor or node is the root node */
8274 if (ancestor == (xmlNodePtr) node->doc) return(1);
8275 if (node == (xmlNodePtr) ancestor->doc) return(0);
8276 while (node->parent != NULL) {
8277 if (node->parent == ancestor)
8278 return(1);
8279 node = node->parent;
8280 }
8281 return(0);
8282}
8283
8284/**
8285 * xmlXPathNextPreceding:
8286 * @ctxt: the XPath Parser context
8287 * @cur: the current node in the traversal
8288 *
8289 * Traversal function for the "preceding" direction
8290 * the preceding axis contains all nodes in the same document as the context
8291 * node that are before the context node in document order, excluding any
8292 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8293 * ordered in reverse document order
8294 *
8295 * Returns the next element following that axis
8296 */
8297xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008298xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8299{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008300 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008301 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008302 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008303 if (cur->type == XML_ATTRIBUTE_NODE) {
8304 cur = cur->parent;
8305 } else if (cur->type == XML_NAMESPACE_DECL) {
8306 xmlNsPtr ns = (xmlNsPtr) cur;
8307
8308 if ((ns->next == NULL) ||
8309 (ns->next->type == XML_NAMESPACE_DECL))
8310 return (NULL);
8311 cur = (xmlNodePtr) ns->next;
8312 }
Daniel Veillardea90b892010-10-22 15:50:50 +02008313 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008314 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008315 return (NULL);
8316 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8317 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008318 do {
8319 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008320 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8321 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008322 }
8323
8324 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008325 if (cur == NULL)
8326 return (NULL);
8327 if (cur == ctxt->context->doc->children)
8328 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008329 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008330 return (cur);
8331}
8332
8333/**
8334 * xmlXPathNextPrecedingInternal:
8335 * @ctxt: the XPath Parser context
8336 * @cur: the current node in the traversal
8337 *
8338 * Traversal function for the "preceding" direction
8339 * the preceding axis contains all nodes in the same document as the context
8340 * node that are before the context node in document order, excluding any
8341 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8342 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008343 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008344 * state kept in the parser context: ctxt->ancestor.
8345 *
8346 * Returns the next element following that axis
8347 */
8348static xmlNodePtr
8349xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8350 xmlNodePtr cur)
8351{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008352 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008353 if (cur == NULL) {
8354 cur = ctxt->context->node;
8355 if (cur == NULL)
8356 return (NULL);
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008357 if (cur->type == XML_ATTRIBUTE_NODE) {
8358 cur = cur->parent;
8359 } else if (cur->type == XML_NAMESPACE_DECL) {
8360 xmlNsPtr ns = (xmlNsPtr) cur;
8361
8362 if ((ns->next == NULL) ||
8363 (ns->next->type == XML_NAMESPACE_DECL))
8364 return (NULL);
8365 cur = (xmlNodePtr) ns->next;
8366 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00008367 ctxt->ancestor = cur->parent;
8368 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008369 if (cur->type == XML_NAMESPACE_DECL)
8370 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008371 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8372 cur = cur->prev;
8373 while (cur->prev == NULL) {
8374 cur = cur->parent;
8375 if (cur == NULL)
8376 return (NULL);
8377 if (cur == ctxt->context->doc->children)
8378 return (NULL);
8379 if (cur != ctxt->ancestor)
8380 return (cur);
8381 ctxt->ancestor = cur->parent;
8382 }
8383 cur = cur->prev;
8384 while (cur->last != NULL)
8385 cur = cur->last;
8386 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008387}
8388
8389/**
8390 * xmlXPathNextNamespace:
8391 * @ctxt: the XPath Parser context
8392 * @cur: the current attribute in the traversal
8393 *
8394 * Traversal function for the "namespace" direction
8395 * the namespace axis contains the namespace nodes of the context node;
8396 * the order of nodes on this axis is implementation-defined; the axis will
8397 * be empty unless the context node is an element
8398 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008399 * We keep the XML namespace node at the end of the list.
8400 *
Owen Taylor3473f882001-02-23 17:55:21 +00008401 * Returns the next element following that axis
8402 */
8403xmlNodePtr
8404xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008405 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008406 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Nick Wellnhofer82b73032016-04-30 17:53:10 +02008407 if (cur == NULL) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008408 if (ctxt->context->tmpNsList != NULL)
8409 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008410 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008411 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008412 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008413 if (ctxt->context->tmpNsList != NULL) {
8414 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8415 ctxt->context->tmpNsNr++;
8416 }
8417 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008418 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008419 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008420 if (ctxt->context->tmpNsNr > 0) {
8421 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8422 } else {
8423 if (ctxt->context->tmpNsList != NULL)
8424 xmlFree(ctxt->context->tmpNsList);
8425 ctxt->context->tmpNsList = NULL;
8426 return(NULL);
8427 }
Owen Taylor3473f882001-02-23 17:55:21 +00008428}
8429
8430/**
8431 * xmlXPathNextAttribute:
8432 * @ctxt: the XPath Parser context
8433 * @cur: the current attribute in the traversal
8434 *
8435 * Traversal function for the "attribute" direction
8436 * TODO: support DTD inherited default attributes
8437 *
8438 * Returns the next element following that axis
8439 */
8440xmlNodePtr
8441xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008442 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008443 if (ctxt->context->node == NULL)
8444 return(NULL);
8445 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8446 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008447 if (cur == NULL) {
8448 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8449 return(NULL);
8450 return((xmlNodePtr)ctxt->context->node->properties);
8451 }
8452 return((xmlNodePtr)cur->next);
8453}
8454
8455/************************************************************************
8456 * *
8457 * NodeTest Functions *
8458 * *
8459 ************************************************************************/
8460
Owen Taylor3473f882001-02-23 17:55:21 +00008461#define IS_FUNCTION 200
8462
Owen Taylor3473f882001-02-23 17:55:21 +00008463
8464/************************************************************************
8465 * *
8466 * Implicit tree core function library *
8467 * *
8468 ************************************************************************/
8469
8470/**
8471 * xmlXPathRoot:
8472 * @ctxt: the XPath Parser context
8473 *
8474 * Initialize the context to the root of the document
8475 */
8476void
8477xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008478 if ((ctxt == NULL) || (ctxt->context == NULL))
8479 return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008480 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
Elliott Hughes7fbecab2019-01-10 16:42:03 -08008481 (xmlNodePtr) ctxt->context->doc));
Owen Taylor3473f882001-02-23 17:55:21 +00008482}
8483
8484/************************************************************************
8485 * *
8486 * The explicit core function library *
8487 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8488 * *
8489 ************************************************************************/
8490
8491
8492/**
8493 * xmlXPathLastFunction:
8494 * @ctxt: the XPath Parser context
8495 * @nargs: the number of arguments
8496 *
8497 * Implement the last() XPath function
8498 * number last()
8499 * The last function returns the number of nodes in the context node list.
8500 */
8501void
8502xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8503 CHECK_ARITY(0);
8504 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008505 valuePush(ctxt,
8506 xmlXPathCacheNewFloat(ctxt->context,
8507 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008508#ifdef DEBUG_EXPR
8509 xmlGenericError(xmlGenericErrorContext,
8510 "last() : %d\n", ctxt->context->contextSize);
8511#endif
8512 } else {
8513 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8514 }
8515}
8516
8517/**
8518 * xmlXPathPositionFunction:
8519 * @ctxt: the XPath Parser context
8520 * @nargs: the number of arguments
8521 *
8522 * Implement the position() XPath function
8523 * number position()
8524 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008525 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008526 * will be equal to last().
8527 */
8528void
8529xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8530 CHECK_ARITY(0);
8531 if (ctxt->context->proximityPosition >= 0) {
8532 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008533 xmlXPathCacheNewFloat(ctxt->context,
8534 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008535#ifdef DEBUG_EXPR
8536 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8537 ctxt->context->proximityPosition);
8538#endif
8539 } else {
8540 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8541 }
8542}
8543
8544/**
8545 * xmlXPathCountFunction:
8546 * @ctxt: the XPath Parser context
8547 * @nargs: the number of arguments
8548 *
8549 * Implement the count() XPath function
8550 * number count(node-set)
8551 */
8552void
8553xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8554 xmlXPathObjectPtr cur;
8555
8556 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008557 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008558 ((ctxt->value->type != XPATH_NODESET) &&
8559 (ctxt->value->type != XPATH_XSLT_TREE)))
8560 XP_ERROR(XPATH_INVALID_TYPE);
8561 cur = valuePop(ctxt);
8562
Daniel Veillard911f49a2001-04-07 15:39:35 +00008563 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008564 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008565 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008566 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8567 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008568 } else {
8569 if ((cur->nodesetval->nodeNr != 1) ||
8570 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008571 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008572 } else {
8573 xmlNodePtr tmp;
8574 int i = 0;
8575
8576 tmp = cur->nodesetval->nodeTab[0];
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008577 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
Daniel Veillardfe703322001-08-14 12:18:09 +00008578 tmp = tmp->children;
8579 while (tmp != NULL) {
8580 tmp = tmp->next;
8581 i++;
8582 }
8583 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008584 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008585 }
8586 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008587 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008588}
8589
8590/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008591 * xmlXPathGetElementsByIds:
8592 * @doc: the document
8593 * @ids: a whitespace separated list of IDs
8594 *
8595 * Selects elements by their unique ID.
8596 *
8597 * Returns a node-set of selected elements.
8598 */
8599static xmlNodeSetPtr
8600xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8601 xmlNodeSetPtr ret;
8602 const xmlChar *cur = ids;
8603 xmlChar *ID;
8604 xmlAttrPtr attr;
8605 xmlNodePtr elem = NULL;
8606
Daniel Veillard7a985a12003-07-06 17:57:42 +00008607 if (ids == NULL) return(NULL);
8608
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008609 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008610 if (ret == NULL)
8611 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008612
William M. Brack76e95df2003-10-18 16:20:14 +00008613 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008614 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008615 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008616 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008617
8618 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008619 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008620 /*
8621 * We used to check the fact that the value passed
8622 * was an NCName, but this generated much troubles for
8623 * me and Aleksey Sanin, people blatantly violated that
8624 * constaint, like Visa3D spec.
8625 * if (xmlValidateNCName(ID, 1) == 0)
8626 */
8627 attr = xmlGetID(doc, ID);
8628 if (attr != NULL) {
8629 if (attr->type == XML_ATTRIBUTE_NODE)
8630 elem = attr->parent;
8631 else if (attr->type == XML_ELEMENT_NODE)
8632 elem = (xmlNodePtr) attr;
8633 else
8634 elem = NULL;
8635 if (elem != NULL)
8636 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008637 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008638 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008639 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008640
William M. Brack76e95df2003-10-18 16:20:14 +00008641 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008642 ids = cur;
8643 }
8644 return(ret);
8645}
8646
8647/**
Owen Taylor3473f882001-02-23 17:55:21 +00008648 * xmlXPathIdFunction:
8649 * @ctxt: the XPath Parser context
8650 * @nargs: the number of arguments
8651 *
8652 * Implement the id() XPath function
8653 * node-set id(object)
8654 * The id function selects elements by their unique ID
8655 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8656 * then the result is the union of the result of applying id to the
8657 * string value of each of the nodes in the argument node-set. When the
8658 * argument to id is of any other type, the argument is converted to a
8659 * string as if by a call to the string function; the string is split
8660 * into a whitespace-separated list of tokens (whitespace is any sequence
8661 * of characters matching the production S); the result is a node-set
8662 * containing the elements in the same document as the context node that
8663 * have a unique ID equal to any of the tokens in the list.
8664 */
8665void
8666xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008667 xmlChar *tokens;
8668 xmlNodeSetPtr ret;
8669 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008670
8671 CHECK_ARITY(1);
8672 obj = valuePop(ctxt);
8673 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008674 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008675 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008676 int i;
8677
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008678 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008679 /*
8680 * FIXME -- in an out-of-memory condition this will behave badly.
8681 * The solution is not clear -- we already popped an item from
8682 * ctxt, so the object is in a corrupt state.
8683 */
Owen Taylor3473f882001-02-23 17:55:21 +00008684
Daniel Veillard911f49a2001-04-07 15:39:35 +00008685 if (obj->nodesetval != NULL) {
8686 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008687 tokens =
8688 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8689 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8690 ret = xmlXPathNodeSetMerge(ret, ns);
8691 xmlXPathFreeNodeSet(ns);
8692 if (tokens != NULL)
8693 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008694 }
Owen Taylor3473f882001-02-23 17:55:21 +00008695 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008696 xmlXPathReleaseObject(ctxt->context, obj);
8697 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008698 return;
8699 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008700 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008701 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008702 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008703 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008704 return;
8705}
8706
8707/**
8708 * xmlXPathLocalNameFunction:
8709 * @ctxt: the XPath Parser context
8710 * @nargs: the number of arguments
8711 *
8712 * Implement the local-name() XPath function
8713 * string local-name(node-set?)
8714 * The local-name function returns a string containing the local part
8715 * of the name of the node in the argument node-set that is first in
8716 * document order. If the node-set is empty or the first node has no
8717 * name, an empty string is returned. If the argument is omitted it
8718 * defaults to the context node.
8719 */
8720void
8721xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8722 xmlXPathObjectPtr cur;
8723
Daniel Veillarda82b1822004-11-08 16:24:57 +00008724 if (ctxt == NULL) return;
8725
Owen Taylor3473f882001-02-23 17:55:21 +00008726 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008727 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8728 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008729 nargs = 1;
8730 }
8731
8732 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008733 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008734 ((ctxt->value->type != XPATH_NODESET) &&
8735 (ctxt->value->type != XPATH_XSLT_TREE)))
8736 XP_ERROR(XPATH_INVALID_TYPE);
8737 cur = valuePop(ctxt);
8738
Daniel Veillard911f49a2001-04-07 15:39:35 +00008739 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008740 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008741 } else {
8742 int i = 0; /* Should be first in document order !!!!! */
8743 switch (cur->nodesetval->nodeTab[i]->type) {
8744 case XML_ELEMENT_NODE:
8745 case XML_ATTRIBUTE_NODE:
8746 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008747 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008748 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008749 else
8750 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008751 xmlXPathCacheNewString(ctxt->context,
8752 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008753 break;
8754 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008755 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008756 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8757 break;
8758 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008759 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008760 }
8761 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008762 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008763}
8764
8765/**
8766 * xmlXPathNamespaceURIFunction:
8767 * @ctxt: the XPath Parser context
8768 * @nargs: the number of arguments
8769 *
8770 * Implement the namespace-uri() XPath function
8771 * string namespace-uri(node-set?)
8772 * The namespace-uri function returns a string containing the
8773 * namespace URI of the expanded name of the node in the argument
8774 * node-set that is first in document order. If the node-set is empty,
8775 * the first node has no name, or the expanded name has no namespace
8776 * URI, an empty string is returned. If the argument is omitted it
8777 * defaults to the context node.
8778 */
8779void
8780xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8781 xmlXPathObjectPtr cur;
8782
Daniel Veillarda82b1822004-11-08 16:24:57 +00008783 if (ctxt == NULL) return;
8784
Owen Taylor3473f882001-02-23 17:55:21 +00008785 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008786 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8787 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008788 nargs = 1;
8789 }
8790 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008791 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008792 ((ctxt->value->type != XPATH_NODESET) &&
8793 (ctxt->value->type != XPATH_XSLT_TREE)))
8794 XP_ERROR(XPATH_INVALID_TYPE);
8795 cur = valuePop(ctxt);
8796
Daniel Veillard911f49a2001-04-07 15:39:35 +00008797 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008798 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008799 } else {
8800 int i = 0; /* Should be first in document order !!!!! */
8801 switch (cur->nodesetval->nodeTab[i]->type) {
8802 case XML_ELEMENT_NODE:
8803 case XML_ATTRIBUTE_NODE:
8804 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008805 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008806 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008807 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008808 cur->nodesetval->nodeTab[i]->ns->href));
8809 break;
8810 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008811 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008812 }
8813 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008814 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008815}
8816
8817/**
8818 * xmlXPathNameFunction:
8819 * @ctxt: the XPath Parser context
8820 * @nargs: the number of arguments
8821 *
8822 * Implement the name() XPath function
8823 * string name(node-set?)
8824 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008825 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008826 * order. The QName must represent the name with respect to the namespace
8827 * declarations in effect on the node whose name is being represented.
8828 * Typically, this will be the form in which the name occurred in the XML
8829 * source. This need not be the case if there are namespace declarations
8830 * in effect on the node that associate multiple prefixes with the same
8831 * namespace. However, an implementation may include information about
8832 * the original prefix in its representation of nodes; in this case, an
8833 * implementation can ensure that the returned string is always the same
8834 * as the QName used in the XML source. If the argument it omitted it
8835 * defaults to the context node.
8836 * Libxml keep the original prefix so the "real qualified name" used is
8837 * returned.
8838 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008839static void
Daniel Veillard04383752001-07-08 14:27:15 +00008840xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8841{
Owen Taylor3473f882001-02-23 17:55:21 +00008842 xmlXPathObjectPtr cur;
8843
8844 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008845 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8846 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008847 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008848 }
8849
8850 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008851 if ((ctxt->value == NULL) ||
8852 ((ctxt->value->type != XPATH_NODESET) &&
8853 (ctxt->value->type != XPATH_XSLT_TREE)))
8854 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008855 cur = valuePop(ctxt);
8856
Daniel Veillard911f49a2001-04-07 15:39:35 +00008857 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008858 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008859 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008860 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008861
Daniel Veillard04383752001-07-08 14:27:15 +00008862 switch (cur->nodesetval->nodeTab[i]->type) {
8863 case XML_ELEMENT_NODE:
8864 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008865 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008866 valuePush(ctxt,
8867 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008868 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8869 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008870 valuePush(ctxt,
8871 xmlXPathCacheNewString(ctxt->context,
8872 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008873 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008874 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008875
Daniel Veillardc00cda82003-04-07 10:22:39 +00008876 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8877 cur->nodesetval->nodeTab[i]->ns->prefix,
8878 NULL, 0);
8879 if (fullname == cur->nodesetval->nodeTab[i]->name)
8880 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8881 if (fullname == NULL) {
8882 XP_ERROR(XPATH_MEMORY_ERROR);
8883 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008884 valuePush(ctxt, xmlXPathCacheWrapString(
8885 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008886 }
8887 break;
8888 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008889 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8890 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008891 xmlXPathLocalNameFunction(ctxt, 1);
8892 }
Owen Taylor3473f882001-02-23 17:55:21 +00008893 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008894 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008895}
8896
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008897
8898/**
Owen Taylor3473f882001-02-23 17:55:21 +00008899 * xmlXPathStringFunction:
8900 * @ctxt: the XPath Parser context
8901 * @nargs: the number of arguments
8902 *
8903 * Implement the string() XPath function
8904 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008905 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008906 * - A node-set is converted to a string by returning the value of
8907 * the node in the node-set that is first in document order.
8908 * If the node-set is empty, an empty string is returned.
8909 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008910 * + NaN is converted to the string NaN
8911 * + positive zero is converted to the string 0
8912 * + negative zero is converted to the string 0
8913 * + positive infinity is converted to the string Infinity
8914 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008915 * + if the number is an integer, the number is represented in
8916 * decimal form as a Number with no decimal point and no leading
8917 * zeros, preceded by a minus sign (-) if the number is negative
8918 * + otherwise, the number is represented in decimal form as a
8919 * Number including a decimal point with at least one digit
8920 * before the decimal point and at least one digit after the
8921 * decimal point, preceded by a minus sign (-) if the number
8922 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008923 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008924 * before the decimal point; beyond the one required digit
8925 * after the decimal point there must be as many, but only as
8926 * many, more digits as are needed to uniquely distinguish the
8927 * number from all other IEEE 754 numeric values.
8928 * - The boolean false value is converted to the string false.
8929 * The boolean true value is converted to the string true.
8930 *
8931 * If the argument is omitted, it defaults to a node-set with the
8932 * context node as its only member.
8933 */
8934void
8935xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8936 xmlXPathObjectPtr cur;
8937
Daniel Veillarda82b1822004-11-08 16:24:57 +00008938 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008939 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008940 valuePush(ctxt,
8941 xmlXPathCacheWrapString(ctxt->context,
8942 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008943 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008944 }
8945
8946 CHECK_ARITY(1);
8947 cur = valuePop(ctxt);
8948 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008949 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008950}
8951
8952/**
8953 * xmlXPathStringLengthFunction:
8954 * @ctxt: the XPath Parser context
8955 * @nargs: the number of arguments
8956 *
8957 * Implement the string-length() XPath function
8958 * number string-length(string?)
8959 * The string-length returns the number of characters in the string
8960 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8961 * the context node converted to a string, in other words the value
8962 * of the context node.
8963 */
8964void
8965xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8966 xmlXPathObjectPtr cur;
8967
8968 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008969 if ((ctxt == NULL) || (ctxt->context == NULL))
8970 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008971 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008972 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008973 } else {
8974 xmlChar *content;
8975
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008976 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008977 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8978 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008979 xmlFree(content);
8980 }
8981 return;
8982 }
8983 CHECK_ARITY(1);
8984 CAST_TO_STRING;
8985 CHECK_TYPE(XPATH_STRING);
8986 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008987 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008988 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008989 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008990}
8991
8992/**
8993 * xmlXPathConcatFunction:
8994 * @ctxt: the XPath Parser context
8995 * @nargs: the number of arguments
8996 *
8997 * Implement the concat() XPath function
8998 * string concat(string, string, string*)
8999 * The concat function returns the concatenation of its arguments.
9000 */
9001void
9002xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9003 xmlXPathObjectPtr cur, newobj;
9004 xmlChar *tmp;
9005
Daniel Veillarda82b1822004-11-08 16:24:57 +00009006 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009007 if (nargs < 2) {
9008 CHECK_ARITY(2);
9009 }
9010
9011 CAST_TO_STRING;
9012 cur = valuePop(ctxt);
9013 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009014 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009015 return;
9016 }
9017 nargs--;
9018
9019 while (nargs > 0) {
9020 CAST_TO_STRING;
9021 newobj = valuePop(ctxt);
9022 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009023 xmlXPathReleaseObject(ctxt->context, newobj);
9024 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009025 XP_ERROR(XPATH_INVALID_TYPE);
9026 }
9027 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9028 newobj->stringval = cur->stringval;
9029 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009030 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00009031 nargs--;
9032 }
9033 valuePush(ctxt, cur);
9034}
9035
9036/**
9037 * xmlXPathContainsFunction:
9038 * @ctxt: the XPath Parser context
9039 * @nargs: the number of arguments
9040 *
9041 * Implement the contains() XPath function
9042 * boolean contains(string, string)
9043 * The contains function returns true if the first argument string
9044 * contains the second argument string, and otherwise returns false.
9045 */
9046void
9047xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9048 xmlXPathObjectPtr hay, needle;
9049
9050 CHECK_ARITY(2);
9051 CAST_TO_STRING;
9052 CHECK_TYPE(XPATH_STRING);
9053 needle = valuePop(ctxt);
9054 CAST_TO_STRING;
9055 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009056
Owen Taylor3473f882001-02-23 17:55:21 +00009057 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009058 xmlXPathReleaseObject(ctxt->context, hay);
9059 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009060 XP_ERROR(XPATH_INVALID_TYPE);
9061 }
9062 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009063 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009064 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009065 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9066 xmlXPathReleaseObject(ctxt->context, hay);
9067 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009068}
9069
9070/**
9071 * xmlXPathStartsWithFunction:
9072 * @ctxt: the XPath Parser context
9073 * @nargs: the number of arguments
9074 *
9075 * Implement the starts-with() XPath function
9076 * boolean starts-with(string, string)
9077 * The starts-with function returns true if the first argument string
9078 * starts with the second argument string, and otherwise returns false.
9079 */
9080void
9081xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9082 xmlXPathObjectPtr hay, needle;
9083 int n;
9084
9085 CHECK_ARITY(2);
9086 CAST_TO_STRING;
9087 CHECK_TYPE(XPATH_STRING);
9088 needle = valuePop(ctxt);
9089 CAST_TO_STRING;
9090 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009091
Owen Taylor3473f882001-02-23 17:55:21 +00009092 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009093 xmlXPathReleaseObject(ctxt->context, hay);
9094 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009095 XP_ERROR(XPATH_INVALID_TYPE);
9096 }
9097 n = xmlStrlen(needle->stringval);
9098 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009099 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009100 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009101 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9102 xmlXPathReleaseObject(ctxt->context, hay);
9103 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009104}
9105
9106/**
9107 * xmlXPathSubstringFunction:
9108 * @ctxt: the XPath Parser context
9109 * @nargs: the number of arguments
9110 *
9111 * Implement the substring() XPath function
9112 * string substring(string, number, number?)
9113 * The substring function returns the substring of the first argument
9114 * starting at the position specified in the second argument with
9115 * length specified in the third argument. For example,
9116 * substring("12345",2,3) returns "234". If the third argument is not
9117 * specified, it returns the substring starting at the position specified
9118 * in the second argument and continuing to the end of the string. For
9119 * example, substring("12345",2) returns "2345". More precisely, each
9120 * character in the string (see [3.6 Strings]) is considered to have a
9121 * numeric position: the position of the first character is 1, the position
9122 * of the second character is 2 and so on. The returned substring contains
9123 * those characters for which the position of the character is greater than
9124 * or equal to the second argument and, if the third argument is specified,
9125 * less than the sum of the second and third arguments; the comparisons
9126 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009127 * - substring("12345", 1.5, 2.6) returns "234"
9128 * - substring("12345", 0, 3) returns "12"
9129 * - substring("12345", 0 div 0, 3) returns ""
9130 * - substring("12345", 1, 0 div 0) returns ""
9131 * - substring("12345", -42, 1 div 0) returns "12345"
9132 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009133 */
9134void
9135xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9136 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009137 double le=0, in;
9138 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009139 xmlChar *ret;
9140
Owen Taylor3473f882001-02-23 17:55:21 +00009141 if (nargs < 2) {
9142 CHECK_ARITY(2);
9143 }
9144 if (nargs > 3) {
9145 CHECK_ARITY(3);
9146 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009147 /*
9148 * take care of possible last (position) argument
9149 */
Owen Taylor3473f882001-02-23 17:55:21 +00009150 if (nargs == 3) {
9151 CAST_TO_NUMBER;
9152 CHECK_TYPE(XPATH_NUMBER);
9153 len = valuePop(ctxt);
9154 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009155 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009156 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009157
Owen Taylor3473f882001-02-23 17:55:21 +00009158 CAST_TO_NUMBER;
9159 CHECK_TYPE(XPATH_NUMBER);
9160 start = valuePop(ctxt);
9161 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009162 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009163 CAST_TO_STRING;
9164 CHECK_TYPE(XPATH_STRING);
9165 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009166 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009167
Daniel Veillard97ac1312001-05-30 19:14:17 +00009168 /*
9169 * If last pos not present, calculate last position
9170 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009171 if (nargs != 3) {
9172 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009173 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009174 in = 1.0;
9175 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009176
Daniel Veillard45490ae2008-07-29 09:13:19 +00009177 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009178 * the index is NaN, the length is NaN, or both
9179 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009180 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009181 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009182 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009183 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009184 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009185 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009186 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009187 * First we go to integer form, rounding up
9188 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009189 */
9190 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009191 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009192
Daniel Veillard9e412302002-06-10 15:59:44 +00009193 if (xmlXPathIsInf(le) == 1) {
9194 l = m;
9195 if (i < 1)
9196 i = 1;
9197 }
9198 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9199 l = 0;
9200 else {
9201 l = (int) le;
9202 if (((double)l)+0.5 <= le) l++;
9203 }
9204
9205 /* Now we normalize inidices */
9206 i -= 1;
9207 l += i;
9208 if (i < 0)
9209 i = 0;
9210 if (l > m)
9211 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009212
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009213 /* number of chars to copy */
9214 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009215
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009216 ret = xmlUTF8Strsub(str->stringval, i, l);
9217 }
9218 else {
9219 ret = NULL;
9220 }
Owen Taylor3473f882001-02-23 17:55:21 +00009221 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009222 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009223 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009224 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009225 xmlFree(ret);
9226 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009227 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009228}
9229
9230/**
9231 * xmlXPathSubstringBeforeFunction:
9232 * @ctxt: the XPath Parser context
9233 * @nargs: the number of arguments
9234 *
9235 * Implement the substring-before() XPath function
9236 * string substring-before(string, string)
9237 * The substring-before function returns the substring of the first
9238 * argument string that precedes the first occurrence of the second
9239 * argument string in the first argument string, or the empty string
9240 * if the first argument string does not contain the second argument
9241 * string. For example, substring-before("1999/04/01","/") returns 1999.
9242 */
9243void
9244xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9245 xmlXPathObjectPtr str;
9246 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009247 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009248 const xmlChar *point;
9249 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009250
Owen Taylor3473f882001-02-23 17:55:21 +00009251 CHECK_ARITY(2);
9252 CAST_TO_STRING;
9253 find = valuePop(ctxt);
9254 CAST_TO_STRING;
9255 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009256
Daniel Veillardade10f22012-07-12 09:43:27 +08009257 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009258 if (target) {
9259 point = xmlStrstr(str->stringval, find->stringval);
9260 if (point) {
9261 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009262 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009263 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009264 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009265 xmlBufContent(target)));
9266 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009267 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009268 xmlXPathReleaseObject(ctxt->context, str);
9269 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009270}
9271
9272/**
9273 * xmlXPathSubstringAfterFunction:
9274 * @ctxt: the XPath Parser context
9275 * @nargs: the number of arguments
9276 *
9277 * Implement the substring-after() XPath function
9278 * string substring-after(string, string)
9279 * The substring-after function returns the substring of the first
9280 * argument string that follows the first occurrence of the second
9281 * argument string in the first argument string, or the empty stringi
9282 * if the first argument string does not contain the second argument
9283 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9284 * and substring-after("1999/04/01","19") returns 99/04/01.
9285 */
9286void
9287xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9288 xmlXPathObjectPtr str;
9289 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009290 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009291 const xmlChar *point;
9292 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009293
Owen Taylor3473f882001-02-23 17:55:21 +00009294 CHECK_ARITY(2);
9295 CAST_TO_STRING;
9296 find = valuePop(ctxt);
9297 CAST_TO_STRING;
9298 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009299
Daniel Veillardade10f22012-07-12 09:43:27 +08009300 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009301 if (target) {
9302 point = xmlStrstr(str->stringval, find->stringval);
9303 if (point) {
9304 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009305 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009306 xmlStrlen(str->stringval) - offset);
9307 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009308 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009309 xmlBufContent(target)));
9310 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009311 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009312 xmlXPathReleaseObject(ctxt->context, str);
9313 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009314}
9315
9316/**
9317 * xmlXPathNormalizeFunction:
9318 * @ctxt: the XPath Parser context
9319 * @nargs: the number of arguments
9320 *
9321 * Implement the normalize-space() XPath function
9322 * string normalize-space(string?)
9323 * The normalize-space function returns the argument string with white
9324 * space normalized by stripping leading and trailing whitespace
9325 * and replacing sequences of whitespace characters by a single
9326 * space. Whitespace characters are the same allowed by the S production
9327 * in XML. If the argument is omitted, it defaults to the context
9328 * node converted to a string, in other words the value of the context node.
9329 */
9330void
9331xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9332 xmlXPathObjectPtr obj = NULL;
9333 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009334 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009335 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009336
Daniel Veillarda82b1822004-11-08 16:24:57 +00009337 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009338 if (nargs == 0) {
9339 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009340 valuePush(ctxt,
9341 xmlXPathCacheWrapString(ctxt->context,
9342 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009343 nargs = 1;
9344 }
9345
9346 CHECK_ARITY(1);
9347 CAST_TO_STRING;
9348 CHECK_TYPE(XPATH_STRING);
9349 obj = valuePop(ctxt);
9350 source = obj->stringval;
9351
Daniel Veillardade10f22012-07-12 09:43:27 +08009352 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009353 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009354
Owen Taylor3473f882001-02-23 17:55:21 +00009355 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009356 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009357 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009358
Owen Taylor3473f882001-02-23 17:55:21 +00009359 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9360 blank = 0;
9361 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009362 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009363 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009364 } else {
9365 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009366 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009367 blank = 0;
9368 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009369 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009370 }
9371 source++;
9372 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009373 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009374 xmlBufContent(target)));
9375 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009376 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009377 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009378}
9379
9380/**
9381 * xmlXPathTranslateFunction:
9382 * @ctxt: the XPath Parser context
9383 * @nargs: the number of arguments
9384 *
9385 * Implement the translate() XPath function
9386 * string translate(string, string, string)
9387 * The translate function returns the first argument string with
9388 * occurrences of characters in the second argument string replaced
9389 * by the character at the corresponding position in the third argument
9390 * string. For example, translate("bar","abc","ABC") returns the string
9391 * BAr. If there is a character in the second argument string with no
9392 * character at a corresponding position in the third argument string
9393 * (because the second argument string is longer than the third argument
9394 * string), then occurrences of that character in the first argument
9395 * string are removed. For example, translate("--aaa--","abc-","ABC")
9396 * returns "AAA". If a character occurs more than once in second
9397 * argument string, then the first occurrence determines the replacement
9398 * character. If the third argument string is longer than the second
9399 * argument string, then excess characters are ignored.
9400 */
9401void
9402xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009403 xmlXPathObjectPtr str;
9404 xmlXPathObjectPtr from;
9405 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009406 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009407 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009408 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009409 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009410 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009411
Daniel Veillarde043ee12001-04-16 14:08:07 +00009412 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009413
Daniel Veillarde043ee12001-04-16 14:08:07 +00009414 CAST_TO_STRING;
9415 to = valuePop(ctxt);
9416 CAST_TO_STRING;
9417 from = valuePop(ctxt);
9418 CAST_TO_STRING;
9419 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009420
Daniel Veillardade10f22012-07-12 09:43:27 +08009421 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009422 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009423 max = xmlUTF8Strlen(to->stringval);
9424 for (cptr = str->stringval; (ch=*cptr); ) {
9425 offset = xmlUTF8Strloc(from->stringval, cptr);
9426 if (offset >= 0) {
9427 if (offset < max) {
9428 point = xmlUTF8Strpos(to->stringval, offset);
9429 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009430 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009431 }
9432 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009433 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009434
9435 /* Step to next character in input */
9436 cptr++;
9437 if ( ch & 0x80 ) {
9438 /* if not simple ascii, verify proper format */
9439 if ( (ch & 0xc0) != 0xc0 ) {
9440 xmlGenericError(xmlGenericErrorContext,
9441 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009442 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009443 break;
9444 }
9445 /* then skip over remaining bytes for this char */
9446 while ( (ch <<= 1) & 0x80 )
9447 if ( (*cptr++ & 0xc0) != 0x80 ) {
9448 xmlGenericError(xmlGenericErrorContext,
9449 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009450 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009451 break;
9452 }
9453 if (ch & 0x80) /* must have had error encountered */
9454 break;
9455 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009456 }
Owen Taylor3473f882001-02-23 17:55:21 +00009457 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009458 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009459 xmlBufContent(target)));
9460 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009461 xmlXPathReleaseObject(ctxt->context, str);
9462 xmlXPathReleaseObject(ctxt->context, from);
9463 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009464}
9465
9466/**
9467 * xmlXPathBooleanFunction:
9468 * @ctxt: the XPath Parser context
9469 * @nargs: the number of arguments
9470 *
9471 * Implement the boolean() XPath function
9472 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009473 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009474 * - a number is true if and only if it is neither positive or
9475 * negative zero nor NaN
9476 * - a node-set is true if and only if it is non-empty
9477 * - a string is true if and only if its length is non-zero
9478 */
9479void
9480xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9481 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009482
9483 CHECK_ARITY(1);
9484 cur = valuePop(ctxt);
9485 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009486 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009487 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009488}
9489
9490/**
9491 * xmlXPathNotFunction:
9492 * @ctxt: the XPath Parser context
9493 * @nargs: the number of arguments
9494 *
9495 * Implement the not() XPath function
9496 * boolean not(boolean)
9497 * The not function returns true if its argument is false,
9498 * and false otherwise.
9499 */
9500void
9501xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9502 CHECK_ARITY(1);
9503 CAST_TO_BOOLEAN;
9504 CHECK_TYPE(XPATH_BOOLEAN);
9505 ctxt->value->boolval = ! ctxt->value->boolval;
9506}
9507
9508/**
9509 * xmlXPathTrueFunction:
9510 * @ctxt: the XPath Parser context
9511 * @nargs: the number of arguments
9512 *
9513 * Implement the true() XPath function
9514 * boolean true()
9515 */
9516void
9517xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9518 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009519 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009520}
9521
9522/**
9523 * xmlXPathFalseFunction:
9524 * @ctxt: the XPath Parser context
9525 * @nargs: the number of arguments
9526 *
9527 * Implement the false() XPath function
9528 * boolean false()
9529 */
9530void
9531xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9532 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009533 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009534}
9535
9536/**
9537 * xmlXPathLangFunction:
9538 * @ctxt: the XPath Parser context
9539 * @nargs: the number of arguments
9540 *
9541 * Implement the lang() XPath function
9542 * boolean lang(string)
9543 * The lang function returns true or false depending on whether the
9544 * language of the context node as specified by xml:lang attributes
9545 * is the same as or is a sublanguage of the language specified by
9546 * the argument string. The language of the context node is determined
9547 * by the value of the xml:lang attribute on the context node, or, if
9548 * the context node has no xml:lang attribute, by the value of the
9549 * xml:lang attribute on the nearest ancestor of the context node that
9550 * has an xml:lang attribute. If there is no such attribute, then lang
9551 * returns false. If there is such an attribute, then lang returns
9552 * true if the attribute value is equal to the argument ignoring case,
9553 * or if there is some suffix starting with - such that the attribute
9554 * value is equal to the argument ignoring that suffix of the attribute
9555 * value and ignoring case.
9556 */
9557void
9558xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009559 xmlXPathObjectPtr val = NULL;
9560 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009561 const xmlChar *lang;
9562 int ret = 0;
9563 int i;
9564
9565 CHECK_ARITY(1);
9566 CAST_TO_STRING;
9567 CHECK_TYPE(XPATH_STRING);
9568 val = valuePop(ctxt);
9569 lang = val->stringval;
9570 theLang = xmlNodeGetLang(ctxt->context->node);
9571 if ((theLang != NULL) && (lang != NULL)) {
9572 for (i = 0;lang[i] != 0;i++)
9573 if (toupper(lang[i]) != toupper(theLang[i]))
9574 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009575 if ((theLang[i] == 0) || (theLang[i] == '-'))
9576 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009577 }
9578not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009579 if (theLang != NULL)
9580 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009581
9582 xmlXPathReleaseObject(ctxt->context, val);
9583 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009584}
9585
9586/**
9587 * xmlXPathNumberFunction:
9588 * @ctxt: the XPath Parser context
9589 * @nargs: the number of arguments
9590 *
9591 * Implement the number() XPath function
9592 * number number(object?)
9593 */
9594void
9595xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9596 xmlXPathObjectPtr cur;
9597 double res;
9598
Daniel Veillarda82b1822004-11-08 16:24:57 +00009599 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009600 if (nargs == 0) {
9601 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009602 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009603 } else {
9604 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9605
9606 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009607 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009608 xmlFree(content);
9609 }
9610 return;
9611 }
9612
9613 CHECK_ARITY(1);
9614 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009615 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009616}
9617
9618/**
9619 * xmlXPathSumFunction:
9620 * @ctxt: the XPath Parser context
9621 * @nargs: the number of arguments
9622 *
9623 * Implement the sum() XPath function
9624 * number sum(node-set)
9625 * The sum function returns the sum of the values of the nodes in
9626 * the argument node-set.
9627 */
9628void
9629xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9630 xmlXPathObjectPtr cur;
9631 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009632 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009633
9634 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009635 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009636 ((ctxt->value->type != XPATH_NODESET) &&
9637 (ctxt->value->type != XPATH_XSLT_TREE)))
9638 XP_ERROR(XPATH_INVALID_TYPE);
9639 cur = valuePop(ctxt);
9640
William M. Brack08171912003-12-29 02:52:11 +00009641 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009642 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9643 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009644 }
9645 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009646 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9647 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009648}
9649
9650/**
9651 * xmlXPathFloorFunction:
9652 * @ctxt: the XPath Parser context
9653 * @nargs: the number of arguments
9654 *
9655 * Implement the floor() XPath function
9656 * number floor(number)
9657 * The floor function returns the largest (closest to positive infinity)
9658 * number that is not greater than the argument and that is an integer.
9659 */
9660void
9661xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9662 CHECK_ARITY(1);
9663 CAST_TO_NUMBER;
9664 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009665
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009666 ctxt->value->floatval = floor(ctxt->value->floatval);
Owen Taylor3473f882001-02-23 17:55:21 +00009667}
9668
9669/**
9670 * xmlXPathCeilingFunction:
9671 * @ctxt: the XPath Parser context
9672 * @nargs: the number of arguments
9673 *
9674 * Implement the ceiling() XPath function
9675 * number ceiling(number)
9676 * The ceiling function returns the smallest (closest to negative infinity)
9677 * number that is not less than the argument and that is an integer.
9678 */
9679void
9680xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Owen Taylor3473f882001-02-23 17:55:21 +00009681 CHECK_ARITY(1);
9682 CAST_TO_NUMBER;
9683 CHECK_TYPE(XPATH_NUMBER);
9684
Owen Taylor3473f882001-02-23 17:55:21 +00009685 ctxt->value->floatval = ceil(ctxt->value->floatval);
Owen Taylor3473f882001-02-23 17:55:21 +00009686}
9687
9688/**
9689 * xmlXPathRoundFunction:
9690 * @ctxt: the XPath Parser context
9691 * @nargs: the number of arguments
9692 *
9693 * Implement the round() XPath function
9694 * number round(number)
9695 * The round function returns the number that is closest to the
9696 * argument and that is an integer. If there are two such numbers,
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009697 * then the one that is closest to positive infinity is returned.
Owen Taylor3473f882001-02-23 17:55:21 +00009698 */
9699void
9700xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9701 double f;
9702
9703 CHECK_ARITY(1);
9704 CAST_TO_NUMBER;
9705 CHECK_TYPE(XPATH_NUMBER);
9706
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009707 f = ctxt->value->floatval;
9708
Nick Wellnhofer8813f392017-09-21 00:11:26 +02009709 if ((f >= -0.5) && (f < 0.5)) {
9710 /* Handles negative zero. */
9711 ctxt->value->floatval *= 0.0;
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009712 }
9713 else {
9714 double rounded = floor(f);
9715 if (f - rounded >= 0.5)
9716 rounded += 1.0;
9717 ctxt->value->floatval = rounded;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009718 }
Owen Taylor3473f882001-02-23 17:55:21 +00009719}
9720
9721/************************************************************************
9722 * *
9723 * The Parser *
9724 * *
9725 ************************************************************************/
9726
9727/*
William M. Brack08171912003-12-29 02:52:11 +00009728 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009729 * implementation.
9730 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009731static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009732static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009733static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009734static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009735static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9736 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009737
9738/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009739 * xmlXPathCurrentChar:
9740 * @ctxt: the XPath parser context
9741 * @cur: pointer to the beginning of the char
9742 * @len: pointer to the length of the char read
9743 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009744 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009745 * bytes in the input buffer.
9746 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009747 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009748 */
9749
9750static int
9751xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9752 unsigned char c;
9753 unsigned int val;
9754 const xmlChar *cur;
9755
9756 if (ctxt == NULL)
9757 return(0);
9758 cur = ctxt->cur;
9759
9760 /*
9761 * We are supposed to handle UTF8, check it's valid
9762 * From rfc2044: encoding of the Unicode values on UTF-8:
9763 *
9764 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9765 * 0000 0000-0000 007F 0xxxxxxx
9766 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009767 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009768 *
9769 * Check for the 0x110000 limit too
9770 */
9771 c = *cur;
9772 if (c & 0x80) {
9773 if ((cur[1] & 0xc0) != 0x80)
9774 goto encoding_error;
9775 if ((c & 0xe0) == 0xe0) {
9776
9777 if ((cur[2] & 0xc0) != 0x80)
9778 goto encoding_error;
9779 if ((c & 0xf0) == 0xf0) {
9780 if (((c & 0xf8) != 0xf0) ||
9781 ((cur[3] & 0xc0) != 0x80))
9782 goto encoding_error;
9783 /* 4-byte code */
9784 *len = 4;
9785 val = (cur[0] & 0x7) << 18;
9786 val |= (cur[1] & 0x3f) << 12;
9787 val |= (cur[2] & 0x3f) << 6;
9788 val |= cur[3] & 0x3f;
9789 } else {
9790 /* 3-byte code */
9791 *len = 3;
9792 val = (cur[0] & 0xf) << 12;
9793 val |= (cur[1] & 0x3f) << 6;
9794 val |= cur[2] & 0x3f;
9795 }
9796 } else {
9797 /* 2-byte code */
9798 *len = 2;
9799 val = (cur[0] & 0x1f) << 6;
9800 val |= cur[1] & 0x3f;
9801 }
9802 if (!IS_CHAR(val)) {
9803 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009804 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009805 return(val);
9806 } else {
9807 /* 1-byte code */
9808 *len = 1;
9809 return((int) *cur);
9810 }
9811encoding_error:
9812 /*
William M. Brack08171912003-12-29 02:52:11 +00009813 * If we detect an UTF8 error that probably means that the
9814 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009815 * declaration header. Report the error and switch the encoding
9816 * to ISO-Latin-1 (if you don't like this policy, just declare the
9817 * encoding !)
9818 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009819 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009820 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009821}
9822
9823/**
Owen Taylor3473f882001-02-23 17:55:21 +00009824 * xmlXPathParseNCName:
9825 * @ctxt: the XPath Parser context
9826 *
9827 * parse an XML namespace non qualified name.
9828 *
9829 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9830 *
9831 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9832 * CombiningChar | Extender
9833 *
9834 * Returns the namespace name or NULL
9835 */
9836
9837xmlChar *
9838xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009839 const xmlChar *in;
9840 xmlChar *ret;
9841 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009842
Daniel Veillarda82b1822004-11-08 16:24:57 +00009843 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009844 /*
9845 * Accelerator for simple ASCII names
9846 */
9847 in = ctxt->cur;
9848 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9849 ((*in >= 0x41) && (*in <= 0x5A)) ||
9850 (*in == '_')) {
9851 in++;
9852 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9853 ((*in >= 0x41) && (*in <= 0x5A)) ||
9854 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009855 (*in == '_') || (*in == '.') ||
9856 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009857 in++;
9858 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9859 (*in == '[') || (*in == ']') || (*in == ':') ||
9860 (*in == '@') || (*in == '*')) {
9861 count = in - ctxt->cur;
9862 if (count == 0)
9863 return(NULL);
9864 ret = xmlStrndup(ctxt->cur, count);
9865 ctxt->cur = in;
9866 return(ret);
9867 }
9868 }
9869 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009870}
9871
Daniel Veillard2156a562001-04-28 12:24:34 +00009872
Owen Taylor3473f882001-02-23 17:55:21 +00009873/**
9874 * xmlXPathParseQName:
9875 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009876 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009877 *
9878 * parse an XML qualified name
9879 *
9880 * [NS 5] QName ::= (Prefix ':')? LocalPart
9881 *
9882 * [NS 6] Prefix ::= NCName
9883 *
9884 * [NS 7] LocalPart ::= NCName
9885 *
9886 * Returns the function returns the local part, and prefix is updated
9887 * to get the Prefix if any.
9888 */
9889
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009890static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009891xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9892 xmlChar *ret = NULL;
9893
9894 *prefix = NULL;
9895 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009896 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009897 *prefix = ret;
9898 NEXT;
9899 ret = xmlXPathParseNCName(ctxt);
9900 }
9901 return(ret);
9902}
9903
9904/**
9905 * xmlXPathParseName:
9906 * @ctxt: the XPath Parser context
9907 *
9908 * parse an XML name
9909 *
9910 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9911 * CombiningChar | Extender
9912 *
9913 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9914 *
9915 * Returns the namespace name or NULL
9916 */
9917
9918xmlChar *
9919xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009920 const xmlChar *in;
9921 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009922 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009923
Daniel Veillarda82b1822004-11-08 16:24:57 +00009924 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009925 /*
9926 * Accelerator for simple ASCII names
9927 */
9928 in = ctxt->cur;
9929 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9930 ((*in >= 0x41) && (*in <= 0x5A)) ||
9931 (*in == '_') || (*in == ':')) {
9932 in++;
9933 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9934 ((*in >= 0x41) && (*in <= 0x5A)) ||
9935 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009936 (*in == '_') || (*in == '-') ||
9937 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009938 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009939 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009940 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009941 if (count > XML_MAX_NAME_LENGTH) {
9942 ctxt->cur = in;
9943 XP_ERRORNULL(XPATH_EXPR_ERROR);
9944 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009945 ret = xmlStrndup(ctxt->cur, count);
9946 ctxt->cur = in;
9947 return(ret);
9948 }
9949 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009950 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009951}
9952
Daniel Veillard61d80a22001-04-27 17:13:01 +00009953static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009954xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009955 xmlChar buf[XML_MAX_NAMELEN + 5];
9956 int len = 0, l;
9957 int c;
9958
9959 /*
9960 * Handler for more complex cases
9961 */
9962 c = CUR_CHAR(l);
9963 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009964 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9965 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009966 (!IS_LETTER(c) && (c != '_') &&
Nick Wellnhofere2893902016-04-21 19:19:23 +02009967 ((!qualified) || (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009968 return(NULL);
9969 }
9970
9971 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9972 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9973 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009974 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009975 (IS_COMBINING(c)) ||
9976 (IS_EXTENDER(c)))) {
9977 COPY_BUF(l,buf,len,c);
9978 NEXTL(l);
9979 c = CUR_CHAR(l);
9980 if (len >= XML_MAX_NAMELEN) {
9981 /*
9982 * Okay someone managed to make a huge name, so he's ready to pay
9983 * for the processing speed.
9984 */
9985 xmlChar *buffer;
9986 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009987
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009988 if (len > XML_MAX_NAME_LENGTH) {
9989 XP_ERRORNULL(XPATH_EXPR_ERROR);
9990 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009991 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009992 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009993 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009994 }
9995 memcpy(buffer, buf, len);
9996 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9997 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009998 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009999 (IS_COMBINING(c)) ||
10000 (IS_EXTENDER(c))) {
10001 if (len + 10 > max) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010002 if (max > XML_MAX_NAME_LENGTH) {
10003 XP_ERRORNULL(XPATH_EXPR_ERROR);
10004 }
Daniel Veillard61d80a22001-04-27 17:13:01 +000010005 max *= 2;
10006 buffer = (xmlChar *) xmlRealloc(buffer,
10007 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010008 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010009 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010010 }
10011 }
10012 COPY_BUF(l,buffer,len,c);
10013 NEXTL(l);
10014 c = CUR_CHAR(l);
10015 }
10016 buffer[len] = 0;
10017 return(buffer);
10018 }
10019 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010020 if (len == 0)
10021 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010022 return(xmlStrndup(buf, len));
10023}
Daniel Veillard3cd72402002-05-13 10:33:30 +000010024
10025#define MAX_FRAC 20
10026
Owen Taylor3473f882001-02-23 17:55:21 +000010027/**
10028 * xmlXPathStringEvalNumber:
10029 * @str: A string to scan
10030 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000010031 * [30a] Float ::= Number ('e' Digits?)?
10032 *
Owen Taylor3473f882001-02-23 17:55:21 +000010033 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010034 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010035 * [31] Digits ::= [0-9]+
10036 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010037 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +000010038 * In complement of the Number expression, this function also handles
10039 * negative values : '-' Number.
10040 *
10041 * Returns the double value.
10042 */
10043double
10044xmlXPathStringEvalNumber(const xmlChar *str) {
10045 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +000010046 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010047 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010048 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010049 int exponent = 0;
10050 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010051#ifdef __GNUC__
10052 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010053 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010054#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010055 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +000010056 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010057 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +020010058 return(NAN);
Owen Taylor3473f882001-02-23 17:55:21 +000010059 }
10060 if (*cur == '-') {
10061 isneg = 1;
10062 cur++;
10063 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010064
10065#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010066 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010067 * tmp/temp is a workaround against a gcc compiler bug
10068 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010069 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010070 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010071 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010072 ret = ret * 10;
10073 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010074 ok = 1;
10075 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010076 temp = (double) tmp;
10077 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010078 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010079#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010080 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010081 while ((*cur >= '0') && (*cur <= '9')) {
10082 ret = ret * 10 + (*cur - '0');
10083 ok = 1;
10084 cur++;
10085 }
10086#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010087
Owen Taylor3473f882001-02-23 17:55:21 +000010088 if (*cur == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010089 int v, frac = 0, max;
Daniel Veillard3cd72402002-05-13 10:33:30 +000010090 double fraction = 0;
10091
Owen Taylor3473f882001-02-23 17:55:21 +000010092 cur++;
10093 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Nick Wellnhofer8813f392017-09-21 00:11:26 +020010094 return(NAN);
Owen Taylor3473f882001-02-23 17:55:21 +000010095 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010096 while (*cur == '0') {
10097 frac = frac + 1;
10098 cur++;
10099 }
10100 max = frac + MAX_FRAC;
10101 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010102 v = (*cur - '0');
10103 fraction = fraction * 10 + v;
10104 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010105 cur++;
10106 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010107 fraction /= pow(10.0, frac);
Daniel Veillard3cd72402002-05-13 10:33:30 +000010108 ret = ret + fraction;
10109 while ((*cur >= '0') && (*cur <= '9'))
10110 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010111 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010112 if ((*cur == 'e') || (*cur == 'E')) {
10113 cur++;
10114 if (*cur == '-') {
10115 is_exponent_negative = 1;
10116 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010117 } else if (*cur == '+') {
10118 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010119 }
10120 while ((*cur >= '0') && (*cur <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010121 if (exponent < 1000000)
10122 exponent = exponent * 10 + (*cur - '0');
Bjorn Reese70a9da52001-04-21 16:57:29 +000010123 cur++;
10124 }
10125 }
William M. Brack76e95df2003-10-18 16:20:14 +000010126 while (IS_BLANK_CH(*cur)) cur++;
Nick Wellnhofer8813f392017-09-21 00:11:26 +020010127 if (*cur != 0) return(NAN);
Owen Taylor3473f882001-02-23 17:55:21 +000010128 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010129 if (is_exponent_negative) exponent = -exponent;
10130 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010131 return(ret);
10132}
10133
10134/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010135 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010136 * @ctxt: the XPath Parser context
10137 *
10138 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010139 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010140 * [31] Digits ::= [0-9]+
10141 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010142 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010143 *
10144 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010145static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010146xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10147{
Owen Taylor3473f882001-02-23 17:55:21 +000010148 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010149 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010150 int exponent = 0;
10151 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010152#ifdef __GNUC__
10153 unsigned long tmp = 0;
10154 double temp;
10155#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010156
10157 CHECK_ERROR;
10158 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10159 XP_ERROR(XPATH_NUMBER_ERROR);
10160 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010161#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010162 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010163 * tmp/temp is a workaround against a gcc compiler bug
10164 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010165 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010166 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010167 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010168 ret = ret * 10;
10169 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010170 ok = 1;
10171 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010172 temp = (double) tmp;
10173 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010174 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010175#else
10176 ret = 0;
10177 while ((CUR >= '0') && (CUR <= '9')) {
10178 ret = ret * 10 + (CUR - '0');
10179 ok = 1;
10180 NEXT;
10181 }
10182#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010183 if (CUR == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010184 int v, frac = 0, max;
Phil Shaferee32ad32010-11-03 20:53:55 +010010185 double fraction = 0;
10186
Owen Taylor3473f882001-02-23 17:55:21 +000010187 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010188 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10189 XP_ERROR(XPATH_NUMBER_ERROR);
10190 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010191 while (CUR == '0') {
10192 frac = frac + 1;
10193 NEXT;
10194 }
10195 max = frac + MAX_FRAC;
10196 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
Phil Shaferee32ad32010-11-03 20:53:55 +010010197 v = (CUR - '0');
10198 fraction = fraction * 10 + v;
10199 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010200 NEXT;
10201 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010202 fraction /= pow(10.0, frac);
Phil Shaferee32ad32010-11-03 20:53:55 +010010203 ret = ret + fraction;
10204 while ((CUR >= '0') && (CUR <= '9'))
10205 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010206 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010207 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010208 NEXT;
10209 if (CUR == '-') {
10210 is_exponent_negative = 1;
10211 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010212 } else if (CUR == '+') {
10213 NEXT;
10214 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010215 while ((CUR >= '0') && (CUR <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010216 if (exponent < 1000000)
10217 exponent = exponent * 10 + (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010218 NEXT;
10219 }
10220 if (is_exponent_negative)
10221 exponent = -exponent;
10222 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010223 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010224 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010225 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010226}
10227
10228/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010229 * xmlXPathParseLiteral:
10230 * @ctxt: the XPath Parser context
10231 *
10232 * Parse a Literal
10233 *
10234 * [29] Literal ::= '"' [^"]* '"'
10235 * | "'" [^']* "'"
10236 *
10237 * Returns the value found or NULL in case of error
10238 */
10239static xmlChar *
10240xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10241 const xmlChar *q;
10242 xmlChar *ret = NULL;
10243
10244 if (CUR == '"') {
10245 NEXT;
10246 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010247 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010248 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010249 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010250 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010251 } else {
10252 ret = xmlStrndup(q, CUR_PTR - q);
10253 NEXT;
10254 }
10255 } else if (CUR == '\'') {
10256 NEXT;
10257 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010258 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010259 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010260 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010261 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010262 } else {
10263 ret = xmlStrndup(q, CUR_PTR - q);
10264 NEXT;
10265 }
10266 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010267 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010268 }
10269 return(ret);
10270}
10271
10272/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010273 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010274 * @ctxt: the XPath Parser context
10275 *
10276 * Parse a Literal and push it on the stack.
10277 *
10278 * [29] Literal ::= '"' [^"]* '"'
10279 * | "'" [^']* "'"
10280 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010281 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010282 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010283static void
10284xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010285 const xmlChar *q;
10286 xmlChar *ret = NULL;
10287
10288 if (CUR == '"') {
10289 NEXT;
10290 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010291 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010292 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010293 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010294 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10295 } else {
10296 ret = xmlStrndup(q, CUR_PTR - q);
10297 NEXT;
10298 }
10299 } else if (CUR == '\'') {
10300 NEXT;
10301 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010302 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010303 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010304 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010305 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10306 } else {
10307 ret = xmlStrndup(q, CUR_PTR - q);
10308 NEXT;
10309 }
10310 } else {
10311 XP_ERROR(XPATH_START_LITERAL_ERROR);
10312 }
10313 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010314 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010315 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010316 xmlFree(ret);
10317}
10318
10319/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010320 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010321 * @ctxt: the XPath Parser context
10322 *
10323 * Parse a VariableReference, evaluate it and push it on the stack.
10324 *
10325 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010326 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010327 * of any of the types that are possible for the value of an expression,
10328 * and may also be of additional types not specified here.
10329 *
10330 * Early evaluation is possible since:
10331 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010332 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010333 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010334 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010335 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010336static void
10337xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010338 xmlChar *name;
10339 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010340
10341 SKIP_BLANKS;
10342 if (CUR != '$') {
10343 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10344 }
10345 NEXT;
10346 name = xmlXPathParseQName(ctxt, &prefix);
10347 if (name == NULL) {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010348 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010349 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10350 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010351 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010352 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10353 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010354 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010355 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
Daniel Veillard47881282012-09-07 14:24:50 +080010356 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
Daniel Veillardb3d14912005-09-04 20:47:39 +000010357 }
Owen Taylor3473f882001-02-23 17:55:21 +000010358}
10359
10360/**
10361 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010362 * @name: a name string
10363 *
10364 * Is the name given a NodeType one.
10365 *
10366 * [38] NodeType ::= 'comment'
10367 * | 'text'
10368 * | 'processing-instruction'
10369 * | 'node'
10370 *
10371 * Returns 1 if true 0 otherwise
10372 */
10373int
10374xmlXPathIsNodeType(const xmlChar *name) {
10375 if (name == NULL)
10376 return(0);
10377
Daniel Veillard1971ee22002-01-31 20:29:19 +000010378 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010379 return(1);
10380 if (xmlStrEqual(name, BAD_CAST "text"))
10381 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010382 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010383 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010384 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010385 return(1);
10386 return(0);
10387}
10388
10389/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010390 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010391 * @ctxt: the XPath Parser context
10392 *
10393 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010394 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010395 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010396 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010397 * pushed on the stack
10398 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010399static void
10400xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010401 xmlChar *name;
10402 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010403 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010404 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010405
10406 name = xmlXPathParseQName(ctxt, &prefix);
10407 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010408 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010409 XP_ERROR(XPATH_EXPR_ERROR);
10410 }
10411 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010412#ifdef DEBUG_EXPR
10413 if (prefix == NULL)
10414 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10415 name);
10416 else
10417 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10418 prefix, name);
10419#endif
10420
Owen Taylor3473f882001-02-23 17:55:21 +000010421 if (CUR != '(') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010422 xmlFree(name);
10423 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010424 XP_ERROR(XPATH_EXPR_ERROR);
10425 }
10426 NEXT;
10427 SKIP_BLANKS;
10428
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010429 /*
10430 * Optimization for count(): we don't need the node-set to be sorted.
10431 */
10432 if ((prefix == NULL) && (name[0] == 'c') &&
10433 xmlStrEqual(name, BAD_CAST "count"))
10434 {
10435 sort = 0;
10436 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010437 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010438 if (CUR != ')') {
10439 while (CUR != 0) {
10440 int op1 = ctxt->comp->last;
10441 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010442 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010443 if (ctxt->error != XPATH_EXPRESSION_OK) {
10444 xmlFree(name);
10445 xmlFree(prefix);
10446 return;
10447 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010448 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10449 nbargs++;
10450 if (CUR == ')') break;
10451 if (CUR != ',') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010452 xmlFree(name);
10453 xmlFree(prefix);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010454 XP_ERROR(XPATH_EXPR_ERROR);
10455 }
10456 NEXT;
10457 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010458 }
Owen Taylor3473f882001-02-23 17:55:21 +000010459 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010460 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10461 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010462 NEXT;
10463 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010464}
10465
10466/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010467 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010468 * @ctxt: the XPath Parser context
10469 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010470 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010471 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010472 * | Literal
10473 * | Number
10474 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010475 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010476 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010477 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010478static void
10479xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010480 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010481 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010482 else if (CUR == '(') {
10483 NEXT;
10484 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010485 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010486 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010487 if (CUR != ')') {
10488 XP_ERROR(XPATH_EXPR_ERROR);
10489 }
10490 NEXT;
10491 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010492 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010493 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010494 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010495 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010496 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010497 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010498 }
10499 SKIP_BLANKS;
10500}
10501
10502/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010503 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010504 * @ctxt: the XPath Parser context
10505 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010506 * [20] FilterExpr ::= PrimaryExpr
10507 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010508 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010509 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010510 * Square brackets are used to filter expressions in the same way that
10511 * they are used in location paths. It is an error if the expression to
10512 * be filtered does not evaluate to a node-set. The context node list
10513 * used for evaluating the expression in square brackets is the node-set
10514 * to be filtered listed in document order.
10515 */
10516
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010517static void
10518xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10519 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010520 CHECK_ERROR;
10521 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010522
Owen Taylor3473f882001-02-23 17:55:21 +000010523 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010524 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010525 SKIP_BLANKS;
10526 }
10527
Daniel Veillard45490ae2008-07-29 09:13:19 +000010528
Owen Taylor3473f882001-02-23 17:55:21 +000010529}
10530
10531/**
10532 * xmlXPathScanName:
10533 * @ctxt: the XPath Parser context
10534 *
10535 * Trickery: parse an XML name but without consuming the input flow
10536 * Needed to avoid insanity in the parser state.
10537 *
10538 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10539 * CombiningChar | Extender
10540 *
10541 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10542 *
10543 * [6] Names ::= Name (S Name)*
10544 *
10545 * Returns the Name parsed or NULL
10546 */
10547
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010548static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010549xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010550 int len = 0, l;
10551 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010552 const xmlChar *cur;
10553 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010554
Daniel Veillard03226812004-11-01 14:55:21 +000010555 cur = ctxt->cur;
10556
10557 c = CUR_CHAR(l);
10558 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10559 (!IS_LETTER(c) && (c != '_') &&
10560 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010561 return(NULL);
10562 }
10563
Daniel Veillard03226812004-11-01 14:55:21 +000010564 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10565 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10566 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010567 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010568 (IS_COMBINING(c)) ||
10569 (IS_EXTENDER(c)))) {
10570 len += l;
10571 NEXTL(l);
10572 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010573 }
Daniel Veillard03226812004-11-01 14:55:21 +000010574 ret = xmlStrndup(cur, ctxt->cur - cur);
10575 ctxt->cur = cur;
10576 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010577}
10578
10579/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010580 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010581 * @ctxt: the XPath Parser context
10582 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010583 * [19] PathExpr ::= LocationPath
10584 * | FilterExpr
10585 * | FilterExpr '/' RelativeLocationPath
10586 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010587 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010588 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010589 * The / operator and // operators combine an arbitrary expression
10590 * and a relative location path. It is an error if the expression
10591 * does not evaluate to a node-set.
10592 * The / operator does composition in the same way as when / is
10593 * used in a location path. As in location paths, // is short for
10594 * /descendant-or-self::node()/.
10595 */
10596
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010597static void
10598xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010599 int lc = 1; /* Should we branch to LocationPath ? */
10600 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10601
10602 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010603 if ((CUR == '$') || (CUR == '(') ||
10604 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010605 (CUR == '\'') || (CUR == '"') ||
10606 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010607 lc = 0;
10608 } else if (CUR == '*') {
10609 /* relative or absolute location path */
10610 lc = 1;
10611 } else if (CUR == '/') {
10612 /* relative or absolute location path */
10613 lc = 1;
10614 } else if (CUR == '@') {
10615 /* relative abbreviated attribute location path */
10616 lc = 1;
10617 } else if (CUR == '.') {
10618 /* relative abbreviated attribute location path */
10619 lc = 1;
10620 } else {
10621 /*
10622 * Problem is finding if we have a name here whether it's:
10623 * - a nodetype
10624 * - a function call in which case it's followed by '('
10625 * - an axis in which case it's followed by ':'
10626 * - a element name
10627 * We do an a priori analysis here rather than having to
10628 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010629 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010630 * read/write/debug.
10631 */
10632 SKIP_BLANKS;
10633 name = xmlXPathScanName(ctxt);
10634 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10635#ifdef DEBUG_STEP
10636 xmlGenericError(xmlGenericErrorContext,
10637 "PathExpr: Axis\n");
10638#endif
10639 lc = 1;
10640 xmlFree(name);
10641 } else if (name != NULL) {
10642 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010643
Daniel Veillard45490ae2008-07-29 09:13:19 +000010644
Owen Taylor3473f882001-02-23 17:55:21 +000010645 while (NXT(len) != 0) {
10646 if (NXT(len) == '/') {
10647 /* element name */
10648#ifdef DEBUG_STEP
10649 xmlGenericError(xmlGenericErrorContext,
10650 "PathExpr: AbbrRelLocation\n");
10651#endif
10652 lc = 1;
10653 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010654 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010655 /* ignore blanks */
10656 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010657 } else if (NXT(len) == ':') {
10658#ifdef DEBUG_STEP
10659 xmlGenericError(xmlGenericErrorContext,
10660 "PathExpr: AbbrRelLocation\n");
10661#endif
10662 lc = 1;
10663 break;
10664 } else if ((NXT(len) == '(')) {
Brian C. Young01c35762017-04-03 12:46:02 -070010665 /* Node Type or Function */
Owen Taylor3473f882001-02-23 17:55:21 +000010666 if (xmlXPathIsNodeType(name)) {
10667#ifdef DEBUG_STEP
10668 xmlGenericError(xmlGenericErrorContext,
10669 "PathExpr: Type search\n");
10670#endif
10671 lc = 1;
Brian C. Young01c35762017-04-03 12:46:02 -070010672#ifdef LIBXML_XPTR_ENABLED
10673 } else if (ctxt->xptr &&
10674 xmlStrEqual(name, BAD_CAST "range-to")) {
10675 lc = 1;
10676#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010677 } else {
10678#ifdef DEBUG_STEP
10679 xmlGenericError(xmlGenericErrorContext,
10680 "PathExpr: function call\n");
10681#endif
10682 lc = 0;
10683 }
10684 break;
10685 } else if ((NXT(len) == '[')) {
10686 /* element name */
10687#ifdef DEBUG_STEP
10688 xmlGenericError(xmlGenericErrorContext,
10689 "PathExpr: AbbrRelLocation\n");
10690#endif
10691 lc = 1;
10692 break;
10693 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10694 (NXT(len) == '=')) {
10695 lc = 1;
10696 break;
10697 } else {
10698 lc = 1;
10699 break;
10700 }
10701 len++;
10702 }
10703 if (NXT(len) == 0) {
10704#ifdef DEBUG_STEP
10705 xmlGenericError(xmlGenericErrorContext,
10706 "PathExpr: AbbrRelLocation\n");
10707#endif
10708 /* element name */
10709 lc = 1;
10710 }
10711 xmlFree(name);
10712 } else {
William M. Brack08171912003-12-29 02:52:11 +000010713 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010714 XP_ERROR(XPATH_EXPR_ERROR);
10715 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010716 }
Owen Taylor3473f882001-02-23 17:55:21 +000010717
10718 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010719 if (CUR == '/') {
10720 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10721 } else {
10722 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010723 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010724 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010725 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010726 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010727 CHECK_ERROR;
10728 if ((CUR == '/') && (NXT(1) == '/')) {
10729 SKIP(2);
10730 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010731
10732 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10733 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010734
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010735 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010736 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010737 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010738 }
10739 }
10740 SKIP_BLANKS;
10741}
10742
10743/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010744 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010745 * @ctxt: the XPath Parser context
10746 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010747 * [18] UnionExpr ::= PathExpr
10748 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010749 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010750 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010751 */
10752
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010753static void
10754xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10755 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010756 CHECK_ERROR;
10757 SKIP_BLANKS;
10758 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010759 int op1 = ctxt->comp->last;
10760 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010761
10762 NEXT;
10763 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010764 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010765
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010766 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10767
Owen Taylor3473f882001-02-23 17:55:21 +000010768 SKIP_BLANKS;
10769 }
Owen Taylor3473f882001-02-23 17:55:21 +000010770}
10771
10772/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010773 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010774 * @ctxt: the XPath Parser context
10775 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010776 * [27] UnaryExpr ::= UnionExpr
10777 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010778 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010779 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010780 */
10781
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010782static void
10783xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010784 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010785 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010786
10787 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010788 while (CUR == '-') {
10789 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010790 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010791 NEXT;
10792 SKIP_BLANKS;
10793 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010794
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010795 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010796 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010797 if (found) {
10798 if (minus)
10799 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10800 else
10801 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010802 }
10803}
10804
10805/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010806 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010807 * @ctxt: the XPath Parser context
10808 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010809 * [26] MultiplicativeExpr ::= UnaryExpr
10810 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10811 * | MultiplicativeExpr 'div' UnaryExpr
10812 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010813 * [34] MultiplyOperator ::= '*'
10814 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010815 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010816 */
10817
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010818static void
10819xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10820 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010821 CHECK_ERROR;
10822 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010823 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010824 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10825 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10826 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010827 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010828
10829 if (CUR == '*') {
10830 op = 0;
10831 NEXT;
10832 } else if (CUR == 'd') {
10833 op = 1;
10834 SKIP(3);
10835 } else if (CUR == 'm') {
10836 op = 2;
10837 SKIP(3);
10838 }
10839 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010840 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010841 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010842 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010843 SKIP_BLANKS;
10844 }
10845}
10846
10847/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010848 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010849 * @ctxt: the XPath Parser context
10850 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010851 * [25] AdditiveExpr ::= MultiplicativeExpr
10852 * | AdditiveExpr '+' MultiplicativeExpr
10853 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010854 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010855 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010856 */
10857
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010858static void
10859xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010860
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010861 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010862 CHECK_ERROR;
10863 SKIP_BLANKS;
10864 while ((CUR == '+') || (CUR == '-')) {
10865 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010866 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010867
10868 if (CUR == '+') plus = 1;
10869 else plus = 0;
10870 NEXT;
10871 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010872 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010873 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010874 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010875 SKIP_BLANKS;
10876 }
10877}
10878
10879/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010880 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010881 * @ctxt: the XPath Parser context
10882 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010883 * [24] RelationalExpr ::= AdditiveExpr
10884 * | RelationalExpr '<' AdditiveExpr
10885 * | RelationalExpr '>' AdditiveExpr
10886 * | RelationalExpr '<=' AdditiveExpr
10887 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010888 *
10889 * A <= B > C is allowed ? Answer from James, yes with
10890 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10891 * which is basically what got implemented.
10892 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010893 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010894 * on the stack
10895 */
10896
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010897static void
10898xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10899 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010900 CHECK_ERROR;
10901 SKIP_BLANKS;
10902 while ((CUR == '<') ||
10903 (CUR == '>') ||
10904 ((CUR == '<') && (NXT(1) == '=')) ||
10905 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010906 int inf, strict;
10907 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010908
10909 if (CUR == '<') inf = 1;
10910 else inf = 0;
10911 if (NXT(1) == '=') strict = 0;
10912 else strict = 1;
10913 NEXT;
10914 if (!strict) NEXT;
10915 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010916 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010917 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010918 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010919 SKIP_BLANKS;
10920 }
10921}
10922
10923/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010924 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010925 * @ctxt: the XPath Parser context
10926 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010927 * [23] EqualityExpr ::= RelationalExpr
10928 * | EqualityExpr '=' RelationalExpr
10929 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010930 *
10931 * A != B != C is allowed ? Answer from James, yes with
10932 * (RelationalExpr = RelationalExpr) = RelationalExpr
10933 * (RelationalExpr != RelationalExpr) != RelationalExpr
10934 * which is basically what got implemented.
10935 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010936 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010937 *
10938 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010939static void
10940xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10941 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010942 CHECK_ERROR;
10943 SKIP_BLANKS;
10944 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010945 int eq;
10946 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010947
10948 if (CUR == '=') eq = 1;
10949 else eq = 0;
10950 NEXT;
10951 if (!eq) NEXT;
10952 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010953 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010954 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010955 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010956 SKIP_BLANKS;
10957 }
10958}
10959
10960/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010961 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010962 * @ctxt: the XPath Parser context
10963 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010964 * [22] AndExpr ::= EqualityExpr
10965 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010966 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010967 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010968 *
10969 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010970static void
10971xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10972 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010973 CHECK_ERROR;
10974 SKIP_BLANKS;
10975 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010976 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010977 SKIP(3);
10978 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010979 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010980 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010981 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010982 SKIP_BLANKS;
10983 }
10984}
10985
10986/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010987 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010988 * @ctxt: the XPath Parser context
10989 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010990 * [14] Expr ::= OrExpr
10991 * [21] OrExpr ::= AndExpr
10992 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010993 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010994 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010995 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010996static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010997xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010998 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010999 CHECK_ERROR;
11000 SKIP_BLANKS;
11001 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011002 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011003 SKIP(2);
11004 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011005 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011006 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011007 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011008 SKIP_BLANKS;
11009 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011010 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011011 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011012 /*
11013 * This is the main place to eliminate sorting for
11014 * operations which don't require a sorted node-set.
11015 * E.g. count().
11016 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011017 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11018 }
Owen Taylor3473f882001-02-23 17:55:21 +000011019}
11020
11021/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011022 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000011023 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011024 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000011025 *
11026 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000011027 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000011028 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011029 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000011030 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011031static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011032xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011033 int op1 = ctxt->comp->last;
11034
11035 SKIP_BLANKS;
11036 if (CUR != '[') {
11037 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11038 }
11039 NEXT;
11040 SKIP_BLANKS;
11041
11042 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011043 /*
11044 * This call to xmlXPathCompileExpr() will deactivate sorting
11045 * of the predicate result.
11046 * TODO: Sorting is still activated for filters, since I'm not
11047 * sure if needed. Normally sorting should not be needed, since
11048 * a filter can only diminish the number of items in a sequence,
11049 * but won't change its order; so if the initial sequence is sorted,
11050 * subsequent sorting is not needed.
11051 */
11052 if (! filter)
11053 xmlXPathCompileExpr(ctxt, 0);
11054 else
11055 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011056 CHECK_ERROR;
11057
11058 if (CUR != ']') {
11059 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11060 }
11061
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011062 if (filter)
11063 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11064 else
11065 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011066
11067 NEXT;
11068 SKIP_BLANKS;
11069}
11070
11071/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011072 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011073 * @ctxt: the XPath Parser context
11074 * @test: pointer to a xmlXPathTestVal
11075 * @type: pointer to a xmlXPathTypeVal
11076 * @prefix: placeholder for a possible name prefix
11077 *
11078 * [7] NodeTest ::= NameTest
11079 * | NodeType '(' ')'
11080 * | 'processing-instruction' '(' Literal ')'
11081 *
11082 * [37] NameTest ::= '*'
11083 * | NCName ':' '*'
11084 * | QName
11085 * [38] NodeType ::= 'comment'
11086 * | 'text'
11087 * | 'processing-instruction'
11088 * | 'node'
11089 *
William M. Brack08171912003-12-29 02:52:11 +000011090 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011091 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011092static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011093xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11094 xmlXPathTypeVal *type, const xmlChar **prefix,
11095 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011096 int blanks;
11097
11098 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11099 STRANGE;
11100 return(NULL);
11101 }
William M. Brack78637da2003-07-31 14:47:38 +000011102 *type = (xmlXPathTypeVal) 0;
11103 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011104 *prefix = NULL;
11105 SKIP_BLANKS;
11106
11107 if ((name == NULL) && (CUR == '*')) {
11108 /*
11109 * All elements
11110 */
11111 NEXT;
11112 *test = NODE_TEST_ALL;
11113 return(NULL);
11114 }
11115
11116 if (name == NULL)
11117 name = xmlXPathParseNCName(ctxt);
11118 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011119 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011120 }
11121
William M. Brack76e95df2003-10-18 16:20:14 +000011122 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011123 SKIP_BLANKS;
11124 if (CUR == '(') {
11125 NEXT;
11126 /*
11127 * NodeType or PI search
11128 */
11129 if (xmlStrEqual(name, BAD_CAST "comment"))
11130 *type = NODE_TYPE_COMMENT;
11131 else if (xmlStrEqual(name, BAD_CAST "node"))
11132 *type = NODE_TYPE_NODE;
11133 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11134 *type = NODE_TYPE_PI;
11135 else if (xmlStrEqual(name, BAD_CAST "text"))
11136 *type = NODE_TYPE_TEXT;
11137 else {
11138 if (name != NULL)
11139 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011140 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011141 }
11142
11143 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011144
Owen Taylor3473f882001-02-23 17:55:21 +000011145 SKIP_BLANKS;
11146 if (*type == NODE_TYPE_PI) {
11147 /*
11148 * Specific case: search a PI by name.
11149 */
Owen Taylor3473f882001-02-23 17:55:21 +000011150 if (name != NULL)
11151 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011152 name = NULL;
11153 if (CUR != ')') {
11154 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011155 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011156 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011157 SKIP_BLANKS;
11158 }
Owen Taylor3473f882001-02-23 17:55:21 +000011159 }
11160 if (CUR != ')') {
11161 if (name != NULL)
11162 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011163 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011164 }
11165 NEXT;
11166 return(name);
11167 }
11168 *test = NODE_TEST_NAME;
11169 if ((!blanks) && (CUR == ':')) {
11170 NEXT;
11171
11172 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011173 * Since currently the parser context don't have a
11174 * namespace list associated:
11175 * The namespace name for this prefix can be computed
11176 * only at evaluation time. The compilation is done
11177 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011178 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011179#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011180 *prefix = xmlXPathNsLookup(ctxt->context, name);
11181 if (name != NULL)
11182 xmlFree(name);
11183 if (*prefix == NULL) {
11184 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11185 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011186#else
11187 *prefix = name;
11188#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011189
11190 if (CUR == '*') {
11191 /*
11192 * All elements
11193 */
11194 NEXT;
11195 *test = NODE_TEST_ALL;
11196 return(NULL);
11197 }
11198
11199 name = xmlXPathParseNCName(ctxt);
11200 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011201 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011202 }
11203 }
11204 return(name);
11205}
11206
11207/**
11208 * xmlXPathIsAxisName:
11209 * @name: a preparsed name token
11210 *
11211 * [6] AxisName ::= 'ancestor'
11212 * | 'ancestor-or-self'
11213 * | 'attribute'
11214 * | 'child'
11215 * | 'descendant'
11216 * | 'descendant-or-self'
11217 * | 'following'
11218 * | 'following-sibling'
11219 * | 'namespace'
11220 * | 'parent'
11221 * | 'preceding'
11222 * | 'preceding-sibling'
11223 * | 'self'
11224 *
11225 * Returns the axis or 0
11226 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011227static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011228xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011229 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011230 switch (name[0]) {
11231 case 'a':
11232 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11233 ret = AXIS_ANCESTOR;
11234 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11235 ret = AXIS_ANCESTOR_OR_SELF;
11236 if (xmlStrEqual(name, BAD_CAST "attribute"))
11237 ret = AXIS_ATTRIBUTE;
11238 break;
11239 case 'c':
11240 if (xmlStrEqual(name, BAD_CAST "child"))
11241 ret = AXIS_CHILD;
11242 break;
11243 case 'd':
11244 if (xmlStrEqual(name, BAD_CAST "descendant"))
11245 ret = AXIS_DESCENDANT;
11246 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11247 ret = AXIS_DESCENDANT_OR_SELF;
11248 break;
11249 case 'f':
11250 if (xmlStrEqual(name, BAD_CAST "following"))
11251 ret = AXIS_FOLLOWING;
11252 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11253 ret = AXIS_FOLLOWING_SIBLING;
11254 break;
11255 case 'n':
11256 if (xmlStrEqual(name, BAD_CAST "namespace"))
11257 ret = AXIS_NAMESPACE;
11258 break;
11259 case 'p':
11260 if (xmlStrEqual(name, BAD_CAST "parent"))
11261 ret = AXIS_PARENT;
11262 if (xmlStrEqual(name, BAD_CAST "preceding"))
11263 ret = AXIS_PRECEDING;
11264 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11265 ret = AXIS_PRECEDING_SIBLING;
11266 break;
11267 case 's':
11268 if (xmlStrEqual(name, BAD_CAST "self"))
11269 ret = AXIS_SELF;
11270 break;
11271 }
11272 return(ret);
11273}
11274
11275/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011276 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011277 * @ctxt: the XPath Parser context
11278 *
11279 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011280 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011281 *
11282 * [12] AbbreviatedStep ::= '.' | '..'
11283 *
11284 * [5] AxisSpecifier ::= AxisName '::'
11285 * | AbbreviatedAxisSpecifier
11286 *
11287 * [13] AbbreviatedAxisSpecifier ::= '@'?
11288 *
11289 * Modified for XPtr range support as:
11290 *
11291 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11292 * | AbbreviatedStep
11293 * | 'range-to' '(' Expr ')' Predicate*
11294 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011295 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011296 * A location step of . is short for self::node(). This is
11297 * particularly useful in conjunction with //. For example, the
11298 * location path .//para is short for
11299 * self::node()/descendant-or-self::node()/child::para
11300 * and so will select all para descendant elements of the context
11301 * node.
11302 * Similarly, a location step of .. is short for parent::node().
11303 * For example, ../title is short for parent::node()/child::title
11304 * and so will select the title children of the parent of the context
11305 * node.
11306 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011307static void
11308xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011309#ifdef LIBXML_XPTR_ENABLED
11310 int rangeto = 0;
11311 int op2 = -1;
11312#endif
11313
Owen Taylor3473f882001-02-23 17:55:21 +000011314 SKIP_BLANKS;
11315 if ((CUR == '.') && (NXT(1) == '.')) {
11316 SKIP(2);
11317 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011318 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11319 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011320 } else if (CUR == '.') {
11321 NEXT;
11322 SKIP_BLANKS;
11323 } else {
11324 xmlChar *name = NULL;
11325 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011326 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011327 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011328 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011329 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011330
11331 /*
11332 * The modification needed for XPointer change to the production
11333 */
11334#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011335 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011336 name = xmlXPathParseNCName(ctxt);
11337 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011338 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011339 xmlFree(name);
11340 SKIP_BLANKS;
11341 if (CUR != '(') {
11342 XP_ERROR(XPATH_EXPR_ERROR);
11343 }
11344 NEXT;
11345 SKIP_BLANKS;
11346
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011347 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011348 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011349 CHECK_ERROR;
11350
11351 SKIP_BLANKS;
11352 if (CUR != ')') {
11353 XP_ERROR(XPATH_EXPR_ERROR);
11354 }
11355 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011356 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011357 goto eval_predicates;
11358 }
11359 }
11360#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011361 if (CUR == '*') {
11362 axis = AXIS_CHILD;
11363 } else {
11364 if (name == NULL)
11365 name = xmlXPathParseNCName(ctxt);
11366 if (name != NULL) {
11367 axis = xmlXPathIsAxisName(name);
11368 if (axis != 0) {
11369 SKIP_BLANKS;
11370 if ((CUR == ':') && (NXT(1) == ':')) {
11371 SKIP(2);
11372 xmlFree(name);
11373 name = NULL;
11374 } else {
11375 /* an element name can conflict with an axis one :-\ */
11376 axis = AXIS_CHILD;
11377 }
Owen Taylor3473f882001-02-23 17:55:21 +000011378 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011379 axis = AXIS_CHILD;
11380 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011381 } else if (CUR == '@') {
11382 NEXT;
11383 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011384 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011385 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011386 }
Owen Taylor3473f882001-02-23 17:55:21 +000011387 }
11388
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011389 if (ctxt->error != XPATH_EXPRESSION_OK) {
11390 xmlFree(name);
11391 return;
11392 }
Owen Taylor3473f882001-02-23 17:55:21 +000011393
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011394 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011395 if (test == 0)
11396 return;
11397
Daniel Veillarded6c5492005-07-23 15:00:22 +000011398 if ((prefix != NULL) && (ctxt->context != NULL) &&
11399 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11400 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11401 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11402 }
11403 }
Owen Taylor3473f882001-02-23 17:55:21 +000011404#ifdef DEBUG_STEP
11405 xmlGenericError(xmlGenericErrorContext,
11406 "Basis : computing new set\n");
11407#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011408
Owen Taylor3473f882001-02-23 17:55:21 +000011409#ifdef DEBUG_STEP
11410 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011411 if (ctxt->value == NULL)
11412 xmlGenericError(xmlGenericErrorContext, "no value\n");
11413 else if (ctxt->value->nodesetval == NULL)
11414 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11415 else
11416 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011417#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011418
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011419#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011420eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011421#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011422 op1 = ctxt->comp->last;
11423 ctxt->comp->last = -1;
11424
Owen Taylor3473f882001-02-23 17:55:21 +000011425 SKIP_BLANKS;
11426 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011427 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011428 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011429
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011430#ifdef LIBXML_XPTR_ENABLED
11431 if (rangeto) {
11432 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11433 } else
11434#endif
11435 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11436 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011437
Owen Taylor3473f882001-02-23 17:55:21 +000011438 }
11439#ifdef DEBUG_STEP
11440 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011441 if (ctxt->value == NULL)
11442 xmlGenericError(xmlGenericErrorContext, "no value\n");
11443 else if (ctxt->value->nodesetval == NULL)
11444 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11445 else
11446 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11447 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011448#endif
11449}
11450
11451/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011452 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011453 * @ctxt: the XPath Parser context
11454 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011455 * [3] RelativeLocationPath ::= Step
11456 * | RelativeLocationPath '/' Step
11457 * | AbbreviatedRelativeLocationPath
11458 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011459 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011460 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011461 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011462static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011463xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011464(xmlXPathParserContextPtr ctxt) {
11465 SKIP_BLANKS;
11466 if ((CUR == '/') && (NXT(1) == '/')) {
11467 SKIP(2);
11468 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011469 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11470 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011471 } else if (CUR == '/') {
11472 NEXT;
11473 SKIP_BLANKS;
11474 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011475 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011476 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011477 SKIP_BLANKS;
11478 while (CUR == '/') {
11479 if ((CUR == '/') && (NXT(1) == '/')) {
11480 SKIP(2);
11481 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011482 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011483 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011484 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011485 } else if (CUR == '/') {
11486 NEXT;
11487 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011488 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011489 }
11490 SKIP_BLANKS;
11491 }
11492}
11493
11494/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011495 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011496 * @ctxt: the XPath Parser context
11497 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011498 * [1] LocationPath ::= RelativeLocationPath
11499 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011500 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011501 * | AbbreviatedAbsoluteLocationPath
11502 * [10] AbbreviatedAbsoluteLocationPath ::=
11503 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011504 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011505 * Compile a location path
11506 *
Owen Taylor3473f882001-02-23 17:55:21 +000011507 * // is short for /descendant-or-self::node()/. For example,
11508 * //para is short for /descendant-or-self::node()/child::para and
11509 * so will select any para element in the document (even a para element
11510 * that is a document element will be selected by //para since the
11511 * document element node is a child of the root node); div//para is
11512 * short for div/descendant-or-self::node()/child::para and so will
11513 * select all para descendants of div children.
11514 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011515static void
11516xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011517 SKIP_BLANKS;
11518 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011519 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011520 } else {
11521 while (CUR == '/') {
11522 if ((CUR == '/') && (NXT(1) == '/')) {
11523 SKIP(2);
11524 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011525 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11526 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011527 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011528 } else if (CUR == '/') {
11529 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011530 SKIP_BLANKS;
11531 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011532 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011533 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011534 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011535 }
Martin729601f2009-10-12 22:42:26 +020011536 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011537 }
11538 }
11539}
11540
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011541/************************************************************************
11542 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011543 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011544 * *
11545 ************************************************************************/
11546
Daniel Veillardf06307e2001-07-03 10:35:50 +000011547static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011548xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11549
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011550#ifdef DEBUG_STEP
11551static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011552xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011553 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011554{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011555 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011556 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011557 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011558 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011559 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011560 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011561 xmlGenericError(xmlGenericErrorContext,
11562 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011563 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011564 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011565 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011566 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011567 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011568 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011569 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011570 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011571 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011572 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011573 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011574 xmlGenericError(xmlGenericErrorContext,
11575 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011576 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011577 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011578 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011579 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011580 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011581 xmlGenericError(xmlGenericErrorContext,
11582 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011583 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011584 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011585 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011586 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011587 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011588 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011589 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011590 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011591 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011592 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011593 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011594 xmlGenericError(xmlGenericErrorContext,
11595 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011596 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011597 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011598 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011599 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011600 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011601 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011602 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011603 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011604 case NODE_TEST_NONE:
11605 xmlGenericError(xmlGenericErrorContext,
11606 " searching for none !!!\n");
11607 break;
11608 case NODE_TEST_TYPE:
11609 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011610 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011611 break;
11612 case NODE_TEST_PI:
11613 xmlGenericError(xmlGenericErrorContext,
11614 " searching for PI !!!\n");
11615 break;
11616 case NODE_TEST_ALL:
11617 xmlGenericError(xmlGenericErrorContext,
11618 " searching for *\n");
11619 break;
11620 case NODE_TEST_NS:
11621 xmlGenericError(xmlGenericErrorContext,
11622 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011623 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011624 break;
11625 case NODE_TEST_NAME:
11626 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011627 " searching for name %s\n", op->value5);
11628 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011629 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011630 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011631 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011632 }
11633 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011634}
11635#endif /* DEBUG_STEP */
11636
11637static int
11638xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11639 xmlXPathStepOpPtr op,
11640 xmlNodeSetPtr set,
11641 int contextSize,
11642 int hasNsNodes)
11643{
11644 if (op->ch1 != -1) {
11645 xmlXPathCompExprPtr comp = ctxt->comp;
11646 /*
11647 * Process inner predicates first.
11648 */
11649 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11650 /*
11651 * TODO: raise an internal error.
11652 */
11653 }
11654 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11655 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11656 CHECK_ERROR0;
11657 if (contextSize <= 0)
11658 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011659 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011660 if (op->ch2 != -1) {
11661 xmlXPathContextPtr xpctxt = ctxt->context;
11662 xmlNodePtr contextNode, oldContextNode;
11663 xmlDocPtr oldContextDoc;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080011664 int oldcs, oldpp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011665 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011666 xmlXPathStepOpPtr exprOp;
11667 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11668
11669#ifdef LIBXML_XPTR_ENABLED
11670 /*
11671 * URGENT TODO: Check the following:
11672 * We don't expect location sets if evaluating prediates, right?
11673 * Only filters should expect location sets, right?
11674 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011675#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011676 /*
11677 * SPEC XPath 1.0:
11678 * "For each node in the node-set to be filtered, the
11679 * PredicateExpr is evaluated with that node as the
11680 * context node, with the number of nodes in the
11681 * node-set as the context size, and with the proximity
11682 * position of the node in the node-set with respect to
11683 * the axis as the context position;"
11684 * @oldset is the node-set" to be filtered.
11685 *
11686 * SPEC XPath 1.0:
11687 * "only predicates change the context position and
11688 * context size (see [2.4 Predicates])."
11689 * Example:
11690 * node-set context pos
11691 * nA 1
11692 * nB 2
11693 * nC 3
11694 * After applying predicate [position() > 1] :
11695 * node-set context pos
11696 * nB 1
11697 * nC 2
11698 */
11699 oldContextNode = xpctxt->node;
11700 oldContextDoc = xpctxt->doc;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080011701 oldcs = xpctxt->contextSize;
11702 oldpp = xpctxt->proximityPosition;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011703 /*
11704 * Get the expression of this predicate.
11705 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011706 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011707 newContextSize = 0;
11708 for (i = 0; i < set->nodeNr; i++) {
11709 if (set->nodeTab[i] == NULL)
11710 continue;
11711
11712 contextNode = set->nodeTab[i];
11713 xpctxt->node = contextNode;
11714 xpctxt->contextSize = contextSize;
11715 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011716
11717 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011718 * Also set the xpath document in case things like
11719 * key() are evaluated in the predicate.
11720 */
11721 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11722 (contextNode->doc != NULL))
11723 xpctxt->doc = contextNode->doc;
11724 /*
11725 * Evaluate the predicate expression with 1 context node
11726 * at a time; this node is packaged into a node set; this
11727 * node set is handed over to the evaluation mechanism.
11728 */
11729 if (contextObj == NULL)
11730 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011731 else {
11732 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11733 contextNode) < 0) {
11734 ctxt->error = XPATH_MEMORY_ERROR;
11735 goto evaluation_exit;
11736 }
11737 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011738
11739 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011740
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011741 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011742
William M. Brack0bcec062007-02-14 02:15:19 +000011743 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11744 xmlXPathNodeSetClear(set, hasNsNodes);
11745 newContextSize = 0;
11746 goto evaluation_exit;
11747 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011748
11749 if (res != 0) {
11750 newContextSize++;
11751 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011752 /*
11753 * Remove the entry from the initial node set.
11754 */
11755 set->nodeTab[i] = NULL;
11756 if (contextNode->type == XML_NAMESPACE_DECL)
11757 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011758 }
11759 if (ctxt->value == contextObj) {
11760 /*
11761 * Don't free the temporary XPath object holding the
11762 * context node, in order to avoid massive recreation
11763 * inside this loop.
11764 */
11765 valuePop(ctxt);
11766 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11767 } else {
11768 /*
11769 * TODO: The object was lost in the evaluation machinery.
11770 * Can this happen? Maybe in internal-error cases.
11771 */
11772 contextObj = NULL;
11773 }
11774 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011775
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011776 if (contextObj != NULL) {
11777 if (ctxt->value == contextObj)
11778 valuePop(ctxt);
11779 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011780 }
William M. Brack0bcec062007-02-14 02:15:19 +000011781evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011782 if (exprRes != NULL)
11783 xmlXPathReleaseObject(ctxt->context, exprRes);
11784 /*
11785 * Reset/invalidate the context.
11786 */
11787 xpctxt->node = oldContextNode;
11788 xpctxt->doc = oldContextDoc;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080011789 xpctxt->contextSize = oldcs;
11790 xpctxt->proximityPosition = oldpp;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011791 return(newContextSize);
11792 }
11793 return(contextSize);
11794}
11795
11796static int
11797xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11798 xmlXPathStepOpPtr op,
11799 xmlNodeSetPtr set,
11800 int contextSize,
11801 int minPos,
11802 int maxPos,
11803 int hasNsNodes)
11804{
11805 if (op->ch1 != -1) {
11806 xmlXPathCompExprPtr comp = ctxt->comp;
11807 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11808 /*
11809 * TODO: raise an internal error.
11810 */
11811 }
11812 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11813 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11814 CHECK_ERROR0;
11815 if (contextSize <= 0)
11816 return(0);
11817 }
11818 /*
11819 * Check if the node set contains a sufficient number of nodes for
11820 * the requested range.
11821 */
11822 if (contextSize < minPos) {
11823 xmlXPathNodeSetClear(set, hasNsNodes);
11824 return(0);
11825 }
11826 if (op->ch2 == -1) {
11827 /*
11828 * TODO: Can this ever happen?
11829 */
11830 return (contextSize);
11831 } else {
11832 xmlDocPtr oldContextDoc;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080011833 int oldcs, oldpp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011834 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011835 xmlXPathStepOpPtr exprOp;
11836 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11837 xmlNodePtr oldContextNode, contextNode = NULL;
11838 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011839 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011840
11841#ifdef LIBXML_XPTR_ENABLED
11842 /*
11843 * URGENT TODO: Check the following:
11844 * We don't expect location sets if evaluating prediates, right?
11845 * Only filters should expect location sets, right?
11846 */
11847#endif /* LIBXML_XPTR_ENABLED */
11848
11849 /*
11850 * Save old context.
11851 */
11852 oldContextNode = xpctxt->node;
11853 oldContextDoc = xpctxt->doc;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080011854 oldcs = xpctxt->contextSize;
11855 oldpp = xpctxt->proximityPosition;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011856 /*
11857 * Get the expression of this predicate.
11858 */
11859 exprOp = &ctxt->comp->steps[op->ch2];
11860 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011861 xmlXPathObjectPtr tmp;
11862
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011863 if (set->nodeTab[i] == NULL)
11864 continue;
11865
11866 contextNode = set->nodeTab[i];
11867 xpctxt->node = contextNode;
11868 xpctxt->contextSize = contextSize;
11869 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011870
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011871 /*
11872 * Initialize the new set.
11873 * Also set the xpath document in case things like
11874 * key() evaluation are attempted on the predicate
11875 */
11876 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11877 (contextNode->doc != NULL))
11878 xpctxt->doc = contextNode->doc;
11879 /*
11880 * Evaluate the predicate expression with 1 context node
11881 * at a time; this node is packaged into a node set; this
11882 * node set is handed over to the evaluation mechanism.
11883 */
11884 if (contextObj == NULL)
11885 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011886 else {
11887 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11888 contextNode) < 0) {
11889 ctxt->error = XPATH_MEMORY_ERROR;
11890 goto evaluation_exit;
11891 }
11892 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011893
11894 valuePush(ctxt, contextObj);
Nick Wellnhofer0f3b8432017-06-01 23:12:19 +020011895 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011896 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011897 xmlXPathPopFrame(ctxt, frame);
Nick Wellnhofer0f3b8432017-06-01 23:12:19 +020011898 tmp = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011899
William M. Brackf1794562007-08-23 12:58:13 +000011900 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011901 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011902 /*
11903 * Free up the result
11904 * then pop off contextObj, which will be freed later
11905 */
11906 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011907 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011908 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011909 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011910 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011911 /* push the result back onto the stack */
11912 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011913
11914 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011915 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011916
11917 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011918 /*
11919 * Fits in the requested range.
11920 */
11921 newContextSize++;
11922 if (minPos == maxPos) {
11923 /*
11924 * Only 1 node was requested.
11925 */
11926 if (contextNode->type == XML_NAMESPACE_DECL) {
11927 /*
11928 * As always: take care of those nasty
11929 * namespace nodes.
11930 */
11931 set->nodeTab[i] = NULL;
11932 }
11933 xmlXPathNodeSetClear(set, hasNsNodes);
11934 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011935 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011936 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011937 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011938 if (pos == maxPos) {
11939 /*
11940 * We are done.
11941 */
11942 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11943 goto evaluation_exit;
11944 }
11945 } else {
11946 /*
11947 * Remove the entry from the initial node set.
11948 */
11949 set->nodeTab[i] = NULL;
11950 if (contextNode->type == XML_NAMESPACE_DECL)
11951 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11952 }
11953 if (exprRes != NULL) {
11954 xmlXPathReleaseObject(ctxt->context, exprRes);
11955 exprRes = NULL;
11956 }
11957 if (ctxt->value == contextObj) {
11958 /*
11959 * Don't free the temporary XPath object holding the
11960 * context node, in order to avoid massive recreation
11961 * inside this loop.
11962 */
11963 valuePop(ctxt);
11964 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11965 } else {
11966 /*
11967 * The object was lost in the evaluation machinery.
11968 * Can this happen? Maybe in case of internal-errors.
11969 */
11970 contextObj = NULL;
11971 }
11972 }
11973 goto evaluation_exit;
11974
11975evaluation_error:
11976 xmlXPathNodeSetClear(set, hasNsNodes);
11977 newContextSize = 0;
11978
11979evaluation_exit:
11980 if (contextObj != NULL) {
11981 if (ctxt->value == contextObj)
11982 valuePop(ctxt);
11983 xmlXPathReleaseObject(xpctxt, contextObj);
11984 }
11985 if (exprRes != NULL)
11986 xmlXPathReleaseObject(ctxt->context, exprRes);
11987 /*
11988 * Reset/invalidate the context.
11989 */
11990 xpctxt->node = oldContextNode;
11991 xpctxt->doc = oldContextDoc;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080011992 xpctxt->contextSize = oldcs;
11993 xpctxt->proximityPosition = oldpp;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011994 return(newContextSize);
11995 }
11996 return(contextSize);
11997}
11998
11999static int
12000xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000012001 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012002 int *maxPos)
12003{
12004
12005 xmlXPathStepOpPtr exprOp;
12006
12007 /*
12008 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12009 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012010
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012011 /*
12012 * If not -1, then ch1 will point to:
12013 * 1) For predicates (XPATH_OP_PREDICATE):
12014 * - an inner predicate operator
12015 * 2) For filters (XPATH_OP_FILTER):
12016 * - an inner filter operater OR
12017 * - an expression selecting the node set.
12018 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012019 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012020 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12021 return(0);
12022
12023 if (op->ch2 != -1) {
12024 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012025 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012026 return(0);
12027
12028 if ((exprOp != NULL) &&
12029 (exprOp->op == XPATH_OP_VALUE) &&
12030 (exprOp->value4 != NULL) &&
12031 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12032 {
Nick Wellnhofera58331a2017-05-29 21:02:21 +020012033 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12034
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012035 /*
12036 * We have a "[n]" predicate here.
12037 * TODO: Unfortunately this simplistic test here is not
12038 * able to detect a position() predicate in compound
12039 * expressions like "[@attr = 'a" and position() = 1],
12040 * and even not the usage of position() in
12041 * "[position() = 1]"; thus - obviously - a position-range,
12042 * like it "[position() < 5]", is also not detected.
12043 * Maybe we could rewrite the AST to ease the optimization.
12044 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012045
Nick Wellnhofera58331a2017-05-29 21:02:21 +020012046 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12047 *maxPos = (int) floatval;
12048 if (floatval == (double) *maxPos)
12049 return(1);
12050 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012051 }
12052 return(0);
12053}
12054
12055static int
12056xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12057 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012058 xmlNodePtr * first, xmlNodePtr * last,
12059 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012060{
12061
12062#define XP_TEST_HIT \
12063 if (hasAxisRange != 0) { \
12064 if (++pos == maxPos) { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012065 if (addNode(seq, cur) < 0) \
12066 ctxt->error = XPATH_MEMORY_ERROR; \
12067 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012068 } else { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012069 if (addNode(seq, cur) < 0) \
12070 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012071 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012072
12073#define XP_TEST_HIT_NS \
12074 if (hasAxisRange != 0) { \
12075 if (++pos == maxPos) { \
12076 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012077 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12078 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012079 goto axis_range_end; } \
12080 } else { \
12081 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012082 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12083 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012084 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012085
12086 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12087 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12088 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12089 const xmlChar *prefix = op->value4;
12090 const xmlChar *name = op->value5;
12091 const xmlChar *URI = NULL;
12092
12093#ifdef DEBUG_STEP
12094 int nbMatches = 0, prevMatches = 0;
12095#endif
12096 int total = 0, hasNsNodes = 0;
12097 /* The popped object holding the context nodes */
12098 xmlXPathObjectPtr obj;
12099 /* The set of context nodes for the node tests */
12100 xmlNodeSetPtr contextSeq;
12101 int contextIdx;
12102 xmlNodePtr contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012103 /* The final resulting node set wrt to all context nodes */
12104 xmlNodeSetPtr outSeq;
12105 /*
12106 * The temporary resulting node set wrt 1 context node.
12107 * Used to feed predicate evaluation.
12108 */
12109 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012110 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012111 /* First predicate operator */
12112 xmlXPathStepOpPtr predOp;
12113 int maxPos; /* The requested position() (when a "[n]" predicate) */
12114 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012115 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012116
12117 xmlXPathTraversalFunction next = NULL;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012118 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012119 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012120 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012121 xmlXPathContextPtr xpctxt = ctxt->context;
12122
12123
12124 CHECK_TYPE0(XPATH_NODESET);
12125 obj = valuePop(ctxt);
12126 /*
12127 * Setup namespaces.
12128 */
12129 if (prefix != NULL) {
12130 URI = xmlXPathNsLookup(xpctxt, prefix);
12131 if (URI == NULL) {
12132 xmlXPathReleaseObject(xpctxt, obj);
12133 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12134 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012135 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012136 /*
12137 * Setup axis.
12138 *
12139 * MAYBE FUTURE TODO: merging optimizations:
12140 * - If the nodes to be traversed wrt to the initial nodes and
12141 * the current axis cannot overlap, then we could avoid searching
12142 * for duplicates during the merge.
12143 * But the question is how/when to evaluate if they cannot overlap.
12144 * Example: if we know that for two initial nodes, the one is
12145 * not in the ancestor-or-self axis of the other, then we could safely
12146 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12147 * the descendant-or-self axis.
12148 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012149 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12150 switch (axis) {
12151 case AXIS_ANCESTOR:
12152 first = NULL;
12153 next = xmlXPathNextAncestor;
12154 break;
12155 case AXIS_ANCESTOR_OR_SELF:
12156 first = NULL;
12157 next = xmlXPathNextAncestorOrSelf;
12158 break;
12159 case AXIS_ATTRIBUTE:
12160 first = NULL;
12161 last = NULL;
12162 next = xmlXPathNextAttribute;
12163 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12164 break;
12165 case AXIS_CHILD:
12166 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012167 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12168 (type == NODE_TYPE_NODE))
12169 {
12170 /*
12171 * Optimization if an element node type is 'element'.
12172 */
12173 next = xmlXPathNextChildElement;
12174 } else
12175 next = xmlXPathNextChild;
12176 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12177 break;
12178 case AXIS_DESCENDANT:
12179 last = NULL;
12180 next = xmlXPathNextDescendant;
12181 break;
12182 case AXIS_DESCENDANT_OR_SELF:
12183 last = NULL;
12184 next = xmlXPathNextDescendantOrSelf;
12185 break;
12186 case AXIS_FOLLOWING:
12187 last = NULL;
12188 next = xmlXPathNextFollowing;
12189 break;
12190 case AXIS_FOLLOWING_SIBLING:
12191 last = NULL;
12192 next = xmlXPathNextFollowingSibling;
12193 break;
12194 case AXIS_NAMESPACE:
12195 first = NULL;
12196 last = NULL;
12197 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12198 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12199 break;
12200 case AXIS_PARENT:
12201 first = NULL;
12202 next = xmlXPathNextParent;
12203 break;
12204 case AXIS_PRECEDING:
12205 first = NULL;
12206 next = xmlXPathNextPrecedingInternal;
12207 break;
12208 case AXIS_PRECEDING_SIBLING:
12209 first = NULL;
12210 next = xmlXPathNextPrecedingSibling;
12211 break;
12212 case AXIS_SELF:
12213 first = NULL;
12214 last = NULL;
12215 next = xmlXPathNextSelf;
12216 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12217 break;
12218 }
12219
12220#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012221 xmlXPathDebugDumpStepAxis(op,
12222 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012223#endif
12224
12225 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012226 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012227 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012228 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012229 contextSeq = obj->nodesetval;
12230 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12231 xmlXPathReleaseObject(xpctxt, obj);
12232 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12233 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012234 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012235 /*
12236 * Predicate optimization ---------------------------------------------
12237 * If this step has a last predicate, which contains a position(),
12238 * then we'll optimize (although not exactly "position()", but only
12239 * the short-hand form, i.e., "[n]".
12240 *
12241 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012242 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012243 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12244 * ROOT -- op->ch1
12245 * PREDICATE -- op->ch2 (predOp)
12246 * PREDICATE -- predOp->ch1 = [parent::bar]
12247 * SORT
12248 * COLLECT 'parent' 'name' 'node' bar
12249 * NODE
12250 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12251 *
12252 */
12253 maxPos = 0;
12254 predOp = NULL;
12255 hasPredicateRange = 0;
12256 hasAxisRange = 0;
12257 if (op->ch2 != -1) {
12258 /*
12259 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12260 */
12261 predOp = &ctxt->comp->steps[op->ch2];
12262 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12263 if (predOp->ch1 != -1) {
12264 /*
12265 * Use the next inner predicate operator.
12266 */
12267 predOp = &ctxt->comp->steps[predOp->ch1];
12268 hasPredicateRange = 1;
12269 } else {
12270 /*
12271 * There's no other predicate than the [n] predicate.
12272 */
12273 predOp = NULL;
12274 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012275 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012276 }
12277 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012278 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012279 /*
12280 * Axis traversal -----------------------------------------------------
12281 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012282 /*
12283 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012284 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012285 * - For the namespace axis, the principal node type is namespace.
12286 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012287 *
12288 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012289 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012290 * select all element children of the context node
12291 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012292 oldContextNode = xpctxt->node;
12293 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012294 outSeq = NULL;
12295 seq = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012296 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012297 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012298
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012299
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012300 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12301 (ctxt->error == XPATH_EXPRESSION_OK)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012302 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012303
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012304 if (seq == NULL) {
12305 seq = xmlXPathNodeSetCreate(NULL);
12306 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012307 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012308 goto error;
12309 }
12310 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012311 /*
12312 * Traverse the axis and test the nodes.
12313 */
12314 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012315 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012316 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012317 do {
12318 cur = next(ctxt, cur);
12319 if (cur == NULL)
12320 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012321
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012322 /*
12323 * QUESTION TODO: What does the "first" and "last" stuff do?
12324 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012325 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012326 if (*first == cur)
12327 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012328 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012329#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012330 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012331#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012332 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012333#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012334 {
12335 break;
12336 }
12337 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012338 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012339 if (*last == cur)
12340 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012341 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012342#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012343 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012344#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012345 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012346#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012347 {
12348 break;
12349 }
12350 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012351
12352 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012353
Daniel Veillardf06307e2001-07-03 10:35:50 +000012354#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012355 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12356#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012357
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012358 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012359 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012360 total = 0;
12361 STRANGE
12362 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012363 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012364 if (type == NODE_TYPE_NODE) {
12365 switch (cur->type) {
12366 case XML_DOCUMENT_NODE:
12367 case XML_HTML_DOCUMENT_NODE:
12368#ifdef LIBXML_DOCB_ENABLED
12369 case XML_DOCB_DOCUMENT_NODE:
12370#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012371 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012372 case XML_ATTRIBUTE_NODE:
12373 case XML_PI_NODE:
12374 case XML_COMMENT_NODE:
12375 case XML_CDATA_SECTION_NODE:
12376 case XML_TEXT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012377 XP_TEST_HIT
12378 break;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012379 case XML_NAMESPACE_DECL: {
12380 if (axis == AXIS_NAMESPACE) {
12381 XP_TEST_HIT_NS
12382 } else {
Nick Wellnhofer6eb08942016-05-05 16:49:00 +020012383 hasNsNodes = 1;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012384 XP_TEST_HIT
12385 }
12386 break;
12387 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012388 default:
12389 break;
12390 }
Nick Wellnhoferb2189572017-11-13 21:23:17 +010012391 } else if (cur->type == (xmlElementType) type) {
Daniel Veillard713434d2012-09-26 10:21:06 +080012392 if (cur->type == XML_NAMESPACE_DECL)
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012393 XP_TEST_HIT_NS
12394 else
12395 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012396 } else if ((type == NODE_TYPE_TEXT) &&
12397 (cur->type == XML_CDATA_SECTION_NODE))
12398 {
12399 XP_TEST_HIT
12400 }
12401 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012402 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012403 if ((cur->type == XML_PI_NODE) &&
12404 ((name == NULL) || xmlStrEqual(name, cur->name)))
12405 {
12406 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012407 }
12408 break;
12409 case NODE_TEST_ALL:
12410 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012411 if (cur->type == XML_ATTRIBUTE_NODE)
12412 {
Nick Wellnhofere8de99f2013-08-05 01:26:25 +020012413 if (prefix == NULL)
12414 {
12415 XP_TEST_HIT
12416 } else if ((cur->ns != NULL) &&
12417 (xmlStrEqual(URI, cur->ns->href)))
12418 {
12419 XP_TEST_HIT
12420 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012421 }
12422 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012423 if (cur->type == XML_NAMESPACE_DECL)
12424 {
12425 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012426 }
12427 } else {
12428 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012429 if (prefix == NULL)
12430 {
12431 XP_TEST_HIT
12432
Daniel Veillardf06307e2001-07-03 10:35:50 +000012433 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012434 (xmlStrEqual(URI, cur->ns->href)))
12435 {
12436 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012437 }
12438 }
12439 }
12440 break;
12441 case NODE_TEST_NS:{
12442 TODO;
12443 break;
12444 }
12445 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012446 if (axis == AXIS_ATTRIBUTE) {
12447 if (cur->type != XML_ATTRIBUTE_NODE)
12448 break;
12449 } else if (axis == AXIS_NAMESPACE) {
12450 if (cur->type != XML_NAMESPACE_DECL)
12451 break;
12452 } else {
12453 if (cur->type != XML_ELEMENT_NODE)
12454 break;
12455 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012456 switch (cur->type) {
12457 case XML_ELEMENT_NODE:
12458 if (xmlStrEqual(name, cur->name)) {
12459 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012460 if (cur->ns == NULL)
12461 {
12462 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012463 }
12464 } else {
12465 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012466 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012467 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012468 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012469 }
12470 }
12471 }
12472 break;
12473 case XML_ATTRIBUTE_NODE:{
12474 xmlAttrPtr attr = (xmlAttrPtr) cur;
12475
12476 if (xmlStrEqual(name, attr->name)) {
12477 if (prefix == NULL) {
12478 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012479 (attr->ns->prefix == NULL))
12480 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012481 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012482 }
12483 } else {
12484 if ((attr->ns != NULL) &&
12485 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012486 attr->ns->href)))
12487 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012488 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012489 }
12490 }
12491 }
12492 break;
12493 }
12494 case XML_NAMESPACE_DECL:
12495 if (cur->type == XML_NAMESPACE_DECL) {
12496 xmlNsPtr ns = (xmlNsPtr) cur;
12497
12498 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012499 && (xmlStrEqual(ns->prefix, name)))
12500 {
12501 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012502 }
12503 }
12504 break;
12505 default:
12506 break;
12507 }
12508 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012509 } /* switch(test) */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012510 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012511
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012512 goto apply_predicates;
12513
Daniel Veillard45490ae2008-07-29 09:13:19 +000012514axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012515 /*
12516 * We have a "/foo[n]", and position() = n was reached.
12517 * Note that we can have as well "/foo/::parent::foo[1]", so
12518 * a duplicate-aware merge is still needed.
12519 * Merge with the result.
12520 */
12521 if (outSeq == NULL) {
12522 outSeq = seq;
12523 seq = NULL;
12524 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012525 outSeq = mergeAndClear(outSeq, seq, 0);
12526 /*
12527 * Break if only a true/false result was requested.
12528 */
12529 if (toBool)
12530 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012531 continue;
12532
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012533first_hit: /* ---------------------------------------------------------- */
12534 /*
12535 * Break if only a true/false result was requested and
12536 * no predicates existed and a node test succeeded.
12537 */
12538 if (outSeq == NULL) {
12539 outSeq = seq;
12540 seq = NULL;
12541 } else
12542 outSeq = mergeAndClear(outSeq, seq, 0);
12543 break;
12544
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012545#ifdef DEBUG_STEP
12546 if (seq != NULL)
12547 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012548#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012549
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012550apply_predicates: /* --------------------------------------------------- */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012551 if (ctxt->error != XPATH_EXPRESSION_OK)
12552 goto error;
12553
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012554 /*
12555 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012556 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012557 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12558 /*
12559 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012560 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012561 /*
12562 * QUESTION TODO: The old predicate evaluation took into
12563 * account location-sets.
12564 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12565 * Do we expect such a set here?
12566 * All what I learned now from the evaluation semantics
12567 * does not indicate that a location-set will be processed
12568 * here, so this looks OK.
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012569 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012570 /*
12571 * Iterate over all predicates, starting with the outermost
12572 * predicate.
12573 * TODO: Problem: we cannot execute the inner predicates first
12574 * since we cannot go back *up* the operator tree!
12575 * Options we have:
12576 * 1) Use of recursive functions (like is it currently done
12577 * via xmlXPathCompOpEval())
12578 * 2) Add a predicate evaluation information stack to the
12579 * context struct
12580 * 3) Change the way the operators are linked; we need a
12581 * "parent" field on xmlXPathStepOp
12582 *
12583 * For the moment, I'll try to solve this with a recursive
12584 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012585 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012586 size = seq->nodeNr;
12587 if (hasPredicateRange != 0)
12588 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12589 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12590 else
12591 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12592 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012593
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012594 if (ctxt->error != XPATH_EXPRESSION_OK) {
12595 total = 0;
12596 goto error;
12597 }
12598 /*
12599 * Add the filtered set of nodes to the result node set.
12600 */
12601 if (newSize == 0) {
12602 /*
12603 * The predicates filtered all nodes out.
12604 */
12605 xmlXPathNodeSetClear(seq, hasNsNodes);
12606 } else if (seq->nodeNr > 0) {
12607 /*
12608 * Add to result set.
12609 */
12610 if (outSeq == NULL) {
12611 if (size != newSize) {
12612 /*
12613 * We need to merge and clear here, since
12614 * the sequence will contained NULLed entries.
12615 */
12616 outSeq = mergeAndClear(NULL, seq, 1);
12617 } else {
12618 outSeq = seq;
12619 seq = NULL;
12620 }
12621 } else
12622 outSeq = mergeAndClear(outSeq, seq,
12623 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012624 /*
12625 * Break if only a true/false result was requested.
12626 */
12627 if (toBool)
12628 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012629 }
12630 } else if (seq->nodeNr > 0) {
12631 /*
12632 * Add to result set.
12633 */
12634 if (outSeq == NULL) {
12635 outSeq = seq;
12636 seq = NULL;
12637 } else {
12638 outSeq = mergeAndClear(outSeq, seq, 0);
12639 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012640 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012641 }
12642
12643error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012644 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012645 /*
12646 * QUESTION TODO: What does this do and why?
12647 * TODO: Do we have to do this also for the "error"
12648 * cleanup further down?
12649 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012650 ctxt->value->boolval = 1;
12651 ctxt->value->user = obj->user;
12652 obj->user = NULL;
12653 obj->boolval = 0;
12654 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012655 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012656
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012657 /*
12658 * Ensure we return at least an emtpy set.
12659 */
12660 if (outSeq == NULL) {
12661 if ((seq != NULL) && (seq->nodeNr == 0))
12662 outSeq = seq;
12663 else
12664 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012665 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012666 }
12667 if ((seq != NULL) && (seq != outSeq)) {
12668 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012669 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012670 /*
12671 * Hand over the result. Better to push the set also in
12672 * case of errors.
12673 */
12674 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12675 /*
12676 * Reset the context node.
12677 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012678 xpctxt->node = oldContextNode;
Nick Wellnhofer82b73032016-04-30 17:53:10 +020012679 /*
12680 * When traversing the namespace axis in "toBool" mode, it's
12681 * possible that tmpNsList wasn't freed.
12682 */
12683 if (xpctxt->tmpNsList != NULL) {
12684 xmlFree(xpctxt->tmpNsList);
12685 xpctxt->tmpNsList = NULL;
12686 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012687
12688#ifdef DEBUG_STEP
12689 xmlGenericError(xmlGenericErrorContext,
12690 "\nExamined %d nodes, found %d nodes at that step\n",
12691 total, nbMatches);
12692#endif
12693
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012694 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012695}
12696
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012697static int
12698xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12699 xmlXPathStepOpPtr op, xmlNodePtr * first);
12700
Daniel Veillardf06307e2001-07-03 10:35:50 +000012701/**
12702 * xmlXPathCompOpEvalFirst:
12703 * @ctxt: the XPath parser context with the compiled expression
12704 * @op: an XPath compiled operation
12705 * @first: the first elem found so far
12706 *
12707 * Evaluate the Precompiled XPath operation searching only the first
12708 * element in document order
12709 *
12710 * Returns the number of examined objects.
12711 */
12712static int
12713xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12714 xmlXPathStepOpPtr op, xmlNodePtr * first)
12715{
12716 int total = 0, cur;
12717 xmlXPathCompExprPtr comp;
12718 xmlXPathObjectPtr arg1, arg2;
12719
Daniel Veillard556c6682001-10-06 09:59:51 +000012720 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012721 comp = ctxt->comp;
12722 switch (op->op) {
12723 case XPATH_OP_END:
12724 return (0);
12725 case XPATH_OP_UNION:
12726 total =
12727 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12728 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012729 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012730 if ((ctxt->value != NULL)
12731 && (ctxt->value->type == XPATH_NODESET)
12732 && (ctxt->value->nodesetval != NULL)
12733 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12734 /*
12735 * limit tree traversing to first node in the result
12736 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012737 /*
12738 * OPTIMIZE TODO: This implicitely sorts
12739 * the result, even if not needed. E.g. if the argument
12740 * of the count() function, no sorting is needed.
12741 * OPTIMIZE TODO: How do we know if the node-list wasn't
12742 * aready sorted?
12743 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012744 if (ctxt->value->nodesetval->nodeNr > 1)
12745 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012746 *first = ctxt->value->nodesetval->nodeTab[0];
12747 }
12748 cur =
12749 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12750 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012751 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012752
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012753 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012754 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012755 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12756 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12757 xmlXPathReleaseObject(ctxt->context, arg1);
12758 xmlXPathReleaseObject(ctxt->context, arg2);
12759 XP_ERROR0(XPATH_INVALID_TYPE);
12760 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012761
12762 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12763 arg2->nodesetval);
12764 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012765 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012766 /* optimizer */
12767 if (total > cur)
12768 xmlXPathCompSwap(op);
12769 return (total + cur);
12770 case XPATH_OP_ROOT:
12771 xmlXPathRoot(ctxt);
12772 return (0);
12773 case XPATH_OP_NODE:
12774 if (op->ch1 != -1)
12775 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012776 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012777 if (op->ch2 != -1)
12778 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012779 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012780 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12781 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012782 return (total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012783 case XPATH_OP_COLLECT:{
12784 if (op->ch1 == -1)
12785 return (total);
12786
12787 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012788 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012789
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012790 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012791 return (total);
12792 }
12793 case XPATH_OP_VALUE:
12794 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012795 xmlXPathCacheObjectCopy(ctxt->context,
12796 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012797 return (0);
12798 case XPATH_OP_SORT:
12799 if (op->ch1 != -1)
12800 total +=
12801 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12802 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012803 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012804 if ((ctxt->value != NULL)
12805 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012806 && (ctxt->value->nodesetval != NULL)
12807 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012808 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12809 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012810#ifdef XP_OPTIMIZED_FILTER_FIRST
12811 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012812 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012813 return (total);
12814#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012815 default:
12816 return (xmlXPathCompOpEval(ctxt, op));
12817 }
12818}
12819
12820/**
12821 * xmlXPathCompOpEvalLast:
12822 * @ctxt: the XPath parser context with the compiled expression
12823 * @op: an XPath compiled operation
12824 * @last: the last elem found so far
12825 *
12826 * Evaluate the Precompiled XPath operation searching only the last
12827 * element in document order
12828 *
William M. Brack08171912003-12-29 02:52:11 +000012829 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012830 */
12831static int
12832xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12833 xmlNodePtr * last)
12834{
12835 int total = 0, cur;
12836 xmlXPathCompExprPtr comp;
12837 xmlXPathObjectPtr arg1, arg2;
12838
Daniel Veillard556c6682001-10-06 09:59:51 +000012839 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012840 comp = ctxt->comp;
12841 switch (op->op) {
12842 case XPATH_OP_END:
12843 return (0);
12844 case XPATH_OP_UNION:
12845 total =
12846 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012847 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012848 if ((ctxt->value != NULL)
12849 && (ctxt->value->type == XPATH_NODESET)
12850 && (ctxt->value->nodesetval != NULL)
12851 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12852 /*
12853 * limit tree traversing to first node in the result
12854 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012855 if (ctxt->value->nodesetval->nodeNr > 1)
12856 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012857 *last =
12858 ctxt->value->nodesetval->nodeTab[ctxt->value->
12859 nodesetval->nodeNr -
12860 1];
12861 }
12862 cur =
12863 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012864 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012865 if ((ctxt->value != NULL)
12866 && (ctxt->value->type == XPATH_NODESET)
12867 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012868 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012869 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012870
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012871 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012872 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012873 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12874 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12875 xmlXPathReleaseObject(ctxt->context, arg1);
12876 xmlXPathReleaseObject(ctxt->context, arg2);
12877 XP_ERROR0(XPATH_INVALID_TYPE);
12878 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012879
12880 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12881 arg2->nodesetval);
12882 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012883 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012884 /* optimizer */
12885 if (total > cur)
12886 xmlXPathCompSwap(op);
12887 return (total + cur);
12888 case XPATH_OP_ROOT:
12889 xmlXPathRoot(ctxt);
12890 return (0);
12891 case XPATH_OP_NODE:
12892 if (op->ch1 != -1)
12893 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012894 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012895 if (op->ch2 != -1)
12896 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012897 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012898 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12899 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012900 return (total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012901 case XPATH_OP_COLLECT:{
12902 if (op->ch1 == -1)
12903 return (0);
12904
12905 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012906 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012907
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012908 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012909 return (total);
12910 }
12911 case XPATH_OP_VALUE:
12912 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012913 xmlXPathCacheObjectCopy(ctxt->context,
12914 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012915 return (0);
12916 case XPATH_OP_SORT:
12917 if (op->ch1 != -1)
12918 total +=
12919 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12920 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012921 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012922 if ((ctxt->value != NULL)
12923 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012924 && (ctxt->value->nodesetval != NULL)
12925 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012926 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12927 return (total);
12928 default:
12929 return (xmlXPathCompOpEval(ctxt, op));
12930 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012931}
12932
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012933#ifdef XP_OPTIMIZED_FILTER_FIRST
12934static int
12935xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12936 xmlXPathStepOpPtr op, xmlNodePtr * first)
12937{
12938 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012939 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012940 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012941 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012942 xmlNodeSetPtr oldset;
12943 xmlNodePtr oldnode;
12944 xmlDocPtr oldDoc;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080012945 int oldcs, oldpp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012946 int i;
12947
12948 CHECK_ERROR0;
12949 comp = ctxt->comp;
12950 /*
12951 * Optimization for ()[last()] selection i.e. the last elem
12952 */
12953 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12954 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12955 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12956 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012957
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012958 if ((f != -1) &&
12959 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12960 (comp->steps[f].value5 == NULL) &&
12961 (comp->steps[f].value == 0) &&
12962 (comp->steps[f].value4 != NULL) &&
12963 (xmlStrEqual
12964 (comp->steps[f].value4, BAD_CAST "last"))) {
12965 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012966
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012967 total +=
12968 xmlXPathCompOpEvalLast(ctxt,
12969 &comp->steps[op->ch1],
12970 &last);
12971 CHECK_ERROR0;
12972 /*
12973 * The nodeset should be in document order,
12974 * Keep only the last value
12975 */
12976 if ((ctxt->value != NULL) &&
12977 (ctxt->value->type == XPATH_NODESET) &&
12978 (ctxt->value->nodesetval != NULL) &&
12979 (ctxt->value->nodesetval->nodeTab != NULL) &&
12980 (ctxt->value->nodesetval->nodeNr > 1)) {
Nick Wellnhofer95a92492017-05-21 15:18:58 +020012981 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012982 *first = *(ctxt->value->nodesetval->nodeTab);
12983 }
12984 return (total);
12985 }
12986 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012987
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012988 if (op->ch1 != -1)
12989 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12990 CHECK_ERROR0;
12991 if (op->ch2 == -1)
12992 return (total);
12993 if (ctxt->value == NULL)
12994 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012995
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012996#ifdef LIBXML_XPTR_ENABLED
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012997 /*
12998 * Hum are we filtering the result of an XPointer expression
12999 */
13000 if (ctxt->value->type == XPATH_LOCATIONSET) {
13001 xmlXPathObjectPtr tmp = NULL;
13002 xmlLocationSetPtr newlocset = NULL;
13003 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013004
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013005 /*
13006 * Extract the old locset, and then evaluate the result of the
13007 * expression for all the element in the locset. use it to grow
13008 * up a new locset.
13009 */
13010 CHECK_TYPE0(XPATH_LOCATIONSET);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013011
13012 if ((ctxt->value->user == NULL) ||
13013 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13014 return (total);
13015
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013016 obj = valuePop(ctxt);
13017 oldlocset = obj->user;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013018 oldnode = ctxt->context->node;
13019 oldcs = ctxt->context->contextSize;
13020 oldpp = ctxt->context->proximityPosition;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013021
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013022 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013023
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013024 for (i = 0; i < oldlocset->locNr; i++) {
13025 /*
13026 * Run the evaluation with a node list made of a
13027 * single item in the nodelocset.
13028 */
13029 ctxt->context->node = oldlocset->locTab[i]->user;
13030 ctxt->context->contextSize = oldlocset->locNr;
13031 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013032 if (tmp == NULL) {
13033 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13034 ctxt->context->node);
13035 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013036 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13037 ctxt->context->node) < 0) {
13038 ctxt->error = XPATH_MEMORY_ERROR;
13039 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013040 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013041 valuePush(ctxt, tmp);
13042 if (op->ch2 != -1)
13043 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13044 if (ctxt->error != XPATH_EXPRESSION_OK) {
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013045 xmlXPtrFreeLocationSet(newlocset);
13046 goto xptr_error;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013047 }
13048 /*
13049 * The result of the evaluation need to be tested to
13050 * decided whether the filter succeeded or not
13051 */
13052 res = valuePop(ctxt);
13053 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13054 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013055 xmlXPathCacheObjectCopy(ctxt->context,
13056 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013057 }
13058 /*
13059 * Cleanup
13060 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013061 if (res != NULL) {
13062 xmlXPathReleaseObject(ctxt->context, res);
13063 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013064 if (ctxt->value == tmp) {
13065 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013066 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013067 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013068 * REVISIT TODO: Don't create a temporary nodeset
13069 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013070 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013071 /* OLD: xmlXPathFreeObject(res); */
13072 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013073 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013074 /*
13075 * Only put the first node in the result, then leave.
13076 */
13077 if (newlocset->locNr > 0) {
13078 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13079 break;
13080 }
13081 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013082 if (tmp != NULL) {
13083 xmlXPathReleaseObject(ctxt->context, tmp);
13084 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013085 /*
13086 * The result is used as the new evaluation locset.
13087 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013088 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013089xptr_error:
13090 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013091 ctxt->context->node = oldnode;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013092 ctxt->context->contextSize = oldcs;
13093 ctxt->context->proximityPosition = oldpp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013094 return (total);
13095 }
13096#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013097
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013098 /*
13099 * Extract the old set, and then evaluate the result of the
13100 * expression for all the element in the set. use it to grow
13101 * up a new set.
13102 */
13103 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013104
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013105 if ((ctxt->value->nodesetval != NULL) &&
13106 (ctxt->value->nodesetval->nodeNr != 0)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013107 xmlNodeSetPtr newset;
13108 xmlXPathObjectPtr tmp = NULL;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013109
13110 obj = valuePop(ctxt);
13111 oldset = obj->nodesetval;
13112 oldnode = ctxt->context->node;
13113 oldDoc = ctxt->context->doc;
13114 oldcs = ctxt->context->contextSize;
13115 oldpp = ctxt->context->proximityPosition;
13116
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013117 /*
13118 * Initialize the new set.
13119 * Also set the xpath document in case things like
13120 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013121 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013122 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013123 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013124
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013125 for (i = 0; i < oldset->nodeNr; i++) {
13126 /*
13127 * Run the evaluation with a node list made of
13128 * a single item in the nodeset.
13129 */
13130 ctxt->context->node = oldset->nodeTab[i];
13131 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13132 (oldset->nodeTab[i]->doc != NULL))
13133 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013134 if (tmp == NULL) {
13135 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13136 ctxt->context->node);
13137 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013138 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13139 ctxt->context->node) < 0) {
13140 ctxt->error = XPATH_MEMORY_ERROR;
13141 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013142 }
13143 valuePush(ctxt, tmp);
13144 ctxt->context->contextSize = oldset->nodeNr;
13145 ctxt->context->proximityPosition = i + 1;
13146 if (op->ch2 != -1)
13147 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13148 if (ctxt->error != XPATH_EXPRESSION_OK) {
13149 xmlXPathFreeNodeSet(newset);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013150 goto error;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013151 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013152 /*
13153 * The result of the evaluation needs to be tested to
13154 * decide whether the filter succeeded or not
13155 */
13156 res = valuePop(ctxt);
13157 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013158 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13159 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013160 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013161 /*
13162 * Cleanup
13163 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013164 if (res != NULL) {
13165 xmlXPathReleaseObject(ctxt->context, res);
13166 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013167 if (ctxt->value == tmp) {
13168 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013169 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013170 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013171 * in order to avoid massive recreation inside this
13172 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013173 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013174 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013175 } else
13176 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013177 /*
13178 * Only put the first node in the result, then leave.
13179 */
13180 if (newset->nodeNr > 0) {
13181 *first = *(newset->nodeTab);
13182 break;
13183 }
13184 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013185 if (tmp != NULL) {
13186 xmlXPathReleaseObject(ctxt->context, tmp);
13187 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013188 /*
13189 * The result is used as the new evaluation set.
13190 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013191 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013192error:
13193 xmlXPathReleaseObject(ctxt->context, obj);
13194 ctxt->context->node = oldnode;
13195 ctxt->context->doc = oldDoc;
13196 ctxt->context->contextSize = oldcs;
13197 ctxt->context->proximityPosition = oldpp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013198 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013199 return(total);
13200}
13201#endif /* XP_OPTIMIZED_FILTER_FIRST */
13202
Owen Taylor3473f882001-02-23 17:55:21 +000013203/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013204 * xmlXPathCompOpEval:
13205 * @ctxt: the XPath parser context with the compiled expression
13206 * @op: an XPath compiled operation
13207 *
13208 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013209 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013210 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013211static int
13212xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13213{
13214 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013215 int equal, ret;
13216 xmlXPathCompExprPtr comp;
13217 xmlXPathObjectPtr arg1, arg2;
13218
Daniel Veillard556c6682001-10-06 09:59:51 +000013219 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013220 comp = ctxt->comp;
13221 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013222 case XPATH_OP_END:
13223 return (0);
13224 case XPATH_OP_AND:
13225 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013226 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013227 xmlXPathBooleanFunction(ctxt, 1);
13228 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13229 return (total);
13230 arg2 = valuePop(ctxt);
13231 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013232 if (ctxt->error) {
13233 xmlXPathFreeObject(arg2);
13234 return(0);
13235 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013236 xmlXPathBooleanFunction(ctxt, 1);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013237 if (ctxt->value != NULL)
13238 ctxt->value->boolval &= arg2->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013239 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013240 return (total);
13241 case XPATH_OP_OR:
13242 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013243 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013244 xmlXPathBooleanFunction(ctxt, 1);
13245 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13246 return (total);
13247 arg2 = valuePop(ctxt);
13248 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013249 if (ctxt->error) {
13250 xmlXPathFreeObject(arg2);
13251 return(0);
13252 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013253 xmlXPathBooleanFunction(ctxt, 1);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013254 if (ctxt->value != NULL)
13255 ctxt->value->boolval |= arg2->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013256 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013257 return (total);
13258 case XPATH_OP_EQUAL:
13259 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013260 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013261 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013262 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013263 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013264 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013265 else
13266 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013267 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013268 return (total);
13269 case XPATH_OP_CMP:
13270 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013271 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013272 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013273 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013274 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013275 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013276 return (total);
13277 case XPATH_OP_PLUS:
13278 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013279 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013280 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013281 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013282 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013283 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013284 if (op->value == 0)
13285 xmlXPathSubValues(ctxt);
13286 else if (op->value == 1)
13287 xmlXPathAddValues(ctxt);
13288 else if (op->value == 2)
13289 xmlXPathValueFlipSign(ctxt);
13290 else if (op->value == 3) {
13291 CAST_TO_NUMBER;
13292 CHECK_TYPE0(XPATH_NUMBER);
13293 }
13294 return (total);
13295 case XPATH_OP_MULT:
13296 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013297 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013298 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013299 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013300 if (op->value == 0)
13301 xmlXPathMultValues(ctxt);
13302 else if (op->value == 1)
13303 xmlXPathDivValues(ctxt);
13304 else if (op->value == 2)
13305 xmlXPathModValues(ctxt);
13306 return (total);
13307 case XPATH_OP_UNION:
13308 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013309 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013310 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013311 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013312
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013313 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013314 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013315 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13316 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13317 xmlXPathReleaseObject(ctxt->context, arg1);
13318 xmlXPathReleaseObject(ctxt->context, arg2);
13319 XP_ERROR0(XPATH_INVALID_TYPE);
13320 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013321
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013322 if ((arg1->nodesetval == NULL) ||
13323 ((arg2->nodesetval != NULL) &&
13324 (arg2->nodesetval->nodeNr != 0)))
13325 {
13326 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13327 arg2->nodesetval);
13328 }
13329
Daniel Veillardf06307e2001-07-03 10:35:50 +000013330 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013331 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013332 return (total);
13333 case XPATH_OP_ROOT:
13334 xmlXPathRoot(ctxt);
13335 return (total);
13336 case XPATH_OP_NODE:
13337 if (op->ch1 != -1)
13338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013339 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013340 if (op->ch2 != -1)
13341 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013342 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013343 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13344 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013345 return (total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013346 case XPATH_OP_COLLECT:{
13347 if (op->ch1 == -1)
13348 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013349
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 Veillard9e7160d2001-03-18 23:17:47 +000013352
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013353 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013354 return (total);
13355 }
13356 case XPATH_OP_VALUE:
13357 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013358 xmlXPathCacheObjectCopy(ctxt->context,
13359 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013360 return (total);
13361 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013362 xmlXPathObjectPtr val;
13363
Daniel Veillardf06307e2001-07-03 10:35:50 +000013364 if (op->ch1 != -1)
13365 total +=
13366 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013367 if (op->value5 == NULL) {
13368 val = xmlXPathVariableLookup(ctxt->context, op->value4);
Nick Wellnhofer3157cf42017-09-20 16:13:29 +020013369 if (val == NULL)
13370 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard556c6682001-10-06 09:59:51 +000013371 valuePush(ctxt, val);
13372 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013373 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013374
Daniel Veillardf06307e2001-07-03 10:35:50 +000013375 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13376 if (URI == NULL) {
13377 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013378 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13379 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013380 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013381 return (total);
13382 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013383 val = xmlXPathVariableLookupNS(ctxt->context,
13384 op->value4, URI);
Nick Wellnhofer3157cf42017-09-20 16:13:29 +020013385 if (val == NULL)
13386 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard556c6682001-10-06 09:59:51 +000013387 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013388 }
13389 return (total);
13390 }
13391 case XPATH_OP_FUNCTION:{
13392 xmlXPathFunction func;
13393 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013394 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013395 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013396
Daniel Veillardf5048b32011-08-18 17:10:13 +080013397 frame = xmlXPathSetFrame(ctxt);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013398 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013399 total +=
13400 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013401 if (ctxt->error != XPATH_EXPRESSION_OK) {
13402 xmlXPathPopFrame(ctxt, frame);
13403 return (total);
13404 }
13405 }
13406 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013407 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013408 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013409 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013410 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013411 return (total);
13412 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013413 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013414 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13415 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013416 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013417 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013418 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013419 return (total);
13420 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013421 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013422 if (op->cache != NULL)
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013423 func = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013424 else {
13425 const xmlChar *URI = NULL;
13426
13427 if (op->value5 == NULL)
13428 func =
13429 xmlXPathFunctionLookup(ctxt->context,
13430 op->value4);
13431 else {
13432 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13433 if (URI == NULL) {
13434 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013435 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13436 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013437 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013438 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013439 return (total);
13440 }
13441 func = xmlXPathFunctionLookupNS(ctxt->context,
13442 op->value4, URI);
13443 }
13444 if (func == NULL) {
13445 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013446 "xmlXPathCompOpEval: function %s not found\n",
13447 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013448 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013449 }
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013450 op->cache = func;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013451 op->cacheURI = (void *) URI;
13452 }
13453 oldFunc = ctxt->context->function;
13454 oldFuncURI = ctxt->context->functionURI;
13455 ctxt->context->function = op->value4;
13456 ctxt->context->functionURI = op->cacheURI;
13457 func(ctxt, op->value);
13458 ctxt->context->function = oldFunc;
13459 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013460 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013461 return (total);
13462 }
13463 case XPATH_OP_ARG:
Nick Wellnhofer07def302014-03-21 19:38:08 +010013464 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013465 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013466 CHECK_ERROR0;
13467 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013468 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013469 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013470 CHECK_ERROR0;
13471 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013472 return (total);
13473 case XPATH_OP_PREDICATE:
13474 case XPATH_OP_FILTER:{
13475 xmlXPathObjectPtr res;
13476 xmlXPathObjectPtr obj, tmp;
13477 xmlNodeSetPtr newset = NULL;
13478 xmlNodeSetPtr oldset;
13479 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013480 xmlDocPtr oldDoc;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013481 int oldcs, oldpp;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013482 int i;
13483
13484 /*
13485 * Optimization for ()[1] selection i.e. the first elem
13486 */
13487 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013488#ifdef XP_OPTIMIZED_FILTER_FIRST
13489 /*
13490 * FILTER TODO: Can we assume that the inner processing
13491 * will result in an ordered list if we have an
13492 * XPATH_OP_FILTER?
13493 * What about an additional field or flag on
13494 * xmlXPathObject like @sorted ? This way we wouln'd need
13495 * to assume anything, so it would be more robust and
13496 * easier to optimize.
13497 */
13498 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13499 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13500#else
13501 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13502#endif
13503 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013504 xmlXPathObjectPtr val;
13505
13506 val = comp->steps[op->ch2].value4;
13507 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13508 (val->floatval == 1.0)) {
13509 xmlNodePtr first = NULL;
13510
13511 total +=
13512 xmlXPathCompOpEvalFirst(ctxt,
13513 &comp->steps[op->ch1],
13514 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013515 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013516 /*
13517 * The nodeset should be in document order,
13518 * Keep only the first value
13519 */
13520 if ((ctxt->value != NULL) &&
13521 (ctxt->value->type == XPATH_NODESET) &&
13522 (ctxt->value->nodesetval != NULL) &&
13523 (ctxt->value->nodesetval->nodeNr > 1))
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013524 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13525 1, 1);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013526 return (total);
13527 }
13528 }
13529 /*
13530 * Optimization for ()[last()] selection i.e. the last elem
13531 */
13532 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13533 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13534 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13535 int f = comp->steps[op->ch2].ch1;
13536
13537 if ((f != -1) &&
13538 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13539 (comp->steps[f].value5 == NULL) &&
13540 (comp->steps[f].value == 0) &&
13541 (comp->steps[f].value4 != NULL) &&
13542 (xmlStrEqual
13543 (comp->steps[f].value4, BAD_CAST "last"))) {
13544 xmlNodePtr last = NULL;
13545
13546 total +=
13547 xmlXPathCompOpEvalLast(ctxt,
13548 &comp->steps[op->ch1],
13549 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013550 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013551 /*
13552 * The nodeset should be in document order,
13553 * Keep only the last value
13554 */
13555 if ((ctxt->value != NULL) &&
13556 (ctxt->value->type == XPATH_NODESET) &&
13557 (ctxt->value->nodesetval != NULL) &&
13558 (ctxt->value->nodesetval->nodeTab != NULL) &&
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013559 (ctxt->value->nodesetval->nodeNr > 1))
13560 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013561 return (total);
13562 }
13563 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013564 /*
13565 * Process inner predicates first.
13566 * Example "index[parent::book][1]":
13567 * ...
13568 * PREDICATE <-- we are here "[1]"
13569 * PREDICATE <-- process "[parent::book]" first
13570 * SORT
13571 * COLLECT 'parent' 'name' 'node' book
13572 * NODE
13573 * ELEM Object is a number : 1
13574 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013575 if (op->ch1 != -1)
13576 total +=
13577 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013578 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013579 if (op->ch2 == -1)
13580 return (total);
13581 if (ctxt->value == NULL)
13582 return (total);
13583
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013584#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013585 /*
13586 * Hum are we filtering the result of an XPointer expression
13587 */
13588 if (ctxt->value->type == XPATH_LOCATIONSET) {
13589 xmlLocationSetPtr newlocset = NULL;
13590 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013591
Daniel Veillardf06307e2001-07-03 10:35:50 +000013592 /*
13593 * Extract the old locset, and then evaluate the result of the
13594 * expression for all the element in the locset. use it to grow
13595 * up a new locset.
13596 */
13597 CHECK_TYPE0(XPATH_LOCATIONSET);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013598
13599 if ((ctxt->value->user == NULL) ||
13600 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13601 return (total);
13602
Daniel Veillardf06307e2001-07-03 10:35:50 +000013603 obj = valuePop(ctxt);
13604 oldlocset = obj->user;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013605 oldnode = ctxt->context->node;
13606 oldcs = ctxt->context->contextSize;
13607 oldpp = ctxt->context->proximityPosition;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013608
Daniel Veillardf06307e2001-07-03 10:35:50 +000013609 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013610
Daniel Veillardf06307e2001-07-03 10:35:50 +000013611 for (i = 0; i < oldlocset->locNr; i++) {
13612 /*
13613 * Run the evaluation with a node list made of a
13614 * single item in the nodelocset.
13615 */
13616 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013617 ctxt->context->contextSize = oldlocset->locNr;
13618 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013619 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13620 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013621 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013622
Daniel Veillardf06307e2001-07-03 10:35:50 +000013623 if (op->ch2 != -1)
13624 total +=
13625 xmlXPathCompOpEval(ctxt,
13626 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013627 if (ctxt->error != XPATH_EXPRESSION_OK) {
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013628 xmlXPtrFreeLocationSet(newlocset);
13629 goto filter_xptr_error;
William M. Brack2c19a7b2005-04-10 01:03:23 +000013630 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013631
Daniel Veillardf06307e2001-07-03 10:35:50 +000013632 /*
13633 * The result of the evaluation need to be tested to
13634 * decided whether the filter succeeded or not
13635 */
13636 res = valuePop(ctxt);
13637 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13638 xmlXPtrLocationSetAdd(newlocset,
13639 xmlXPathObjectCopy
13640 (oldlocset->locTab[i]));
13641 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013642
Daniel Veillardf06307e2001-07-03 10:35:50 +000013643 /*
13644 * Cleanup
13645 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013646 if (res != NULL) {
13647 xmlXPathReleaseObject(ctxt->context, res);
13648 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013649 if (ctxt->value == tmp) {
13650 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013651 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013652 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013653 }
13654
13655 /*
13656 * The result is used as the new evaluation locset.
13657 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013658 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013659filter_xptr_error:
13660 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013661 ctxt->context->node = oldnode;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013662 ctxt->context->contextSize = oldcs;
13663 ctxt->context->proximityPosition = oldpp;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013664 return (total);
13665 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013666#endif /* LIBXML_XPTR_ENABLED */
13667
Daniel Veillardf06307e2001-07-03 10:35:50 +000013668 /*
13669 * Extract the old set, and then evaluate the result of the
13670 * expression for all the element in the set. use it to grow
13671 * up a new set.
13672 */
13673 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillard911f49a2001-04-07 15:39:35 +000013674
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013675 if ((ctxt->value->nodesetval != NULL) &&
13676 (ctxt->value->nodesetval->nodeNr != 0)) {
13677 obj = valuePop(ctxt);
13678 oldset = obj->nodesetval;
13679 oldnode = ctxt->context->node;
13680 oldDoc = ctxt->context->doc;
13681 oldcs = ctxt->context->contextSize;
13682 oldpp = ctxt->context->proximityPosition;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013683 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013684 /*
13685 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013686 * Also set the xpath document in case things like
13687 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013688 */
13689 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013690 /*
13691 * SPEC XPath 1.0:
13692 * "For each node in the node-set to be filtered, the
13693 * PredicateExpr is evaluated with that node as the
13694 * context node, with the number of nodes in the
13695 * node-set as the context size, and with the proximity
13696 * position of the node in the node-set with respect to
13697 * the axis as the context position;"
13698 * @oldset is the node-set" to be filtered.
13699 *
13700 * SPEC XPath 1.0:
13701 * "only predicates change the context position and
13702 * context size (see [2.4 Predicates])."
13703 * Example:
13704 * node-set context pos
13705 * nA 1
13706 * nB 2
13707 * nC 3
13708 * After applying predicate [position() > 1] :
13709 * node-set context pos
13710 * nB 1
13711 * nC 2
13712 *
13713 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013714 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013715 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013716 for (i = 0; i < oldset->nodeNr; i++) {
13717 /*
13718 * Run the evaluation with a node list made of
13719 * a single item in the nodeset.
13720 */
13721 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013722 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13723 (oldset->nodeTab[i]->doc != NULL))
13724 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013725 if (tmp == NULL) {
13726 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13727 ctxt->context->node);
13728 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013729 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13730 ctxt->context->node) < 0) {
13731 ctxt->error = XPATH_MEMORY_ERROR;
13732 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013733 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013734 valuePush(ctxt, tmp);
13735 ctxt->context->contextSize = oldset->nodeNr;
13736 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013737 /*
13738 * Evaluate the predicate against the context node.
13739 * Can/should we optimize position() predicates
13740 * here (e.g. "[1]")?
13741 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013742 if (op->ch2 != -1)
13743 total +=
13744 xmlXPathCompOpEval(ctxt,
13745 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013746 if (ctxt->error != XPATH_EXPRESSION_OK) {
13747 xmlXPathFreeNodeSet(newset);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013748 goto filter_error;
William M. Brack2c19a7b2005-04-10 01:03:23 +000013749 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013750
Daniel Veillardf06307e2001-07-03 10:35:50 +000013751 /*
William M. Brack08171912003-12-29 02:52:11 +000013752 * The result of the evaluation needs to be tested to
13753 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013754 */
13755 /*
13756 * OPTIMIZE TODO: Can we use
13757 * xmlXPathNodeSetAdd*Unique()* instead?
13758 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013759 res = valuePop(ctxt);
13760 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013761 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13762 < 0)
13763 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013764 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013765
Daniel Veillardf06307e2001-07-03 10:35:50 +000013766 /*
13767 * Cleanup
13768 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013769 if (res != NULL) {
13770 xmlXPathReleaseObject(ctxt->context, res);
13771 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013772 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013773 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013774 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013775 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013776 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013777 * in order to avoid massive recreation inside this
13778 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013779 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013780 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013781 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013782 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013783 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013784 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013785 /*
13786 * The result is used as the new evaluation set.
13787 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013788 valuePush(ctxt,
13789 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013790filter_error:
13791 xmlXPathReleaseObject(ctxt->context, obj);
13792 ctxt->context->node = oldnode;
13793 ctxt->context->doc = oldDoc;
13794 ctxt->context->contextSize = oldcs;
13795 ctxt->context->proximityPosition = oldpp;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013796 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013797 return (total);
13798 }
13799 case XPATH_OP_SORT:
13800 if (op->ch1 != -1)
13801 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013802 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013803 if ((ctxt->value != NULL) &&
13804 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013805 (ctxt->value->nodesetval != NULL) &&
13806 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013807 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013808 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013809 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013810 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013811#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013812 case XPATH_OP_RANGETO:{
13813 xmlXPathObjectPtr range;
13814 xmlXPathObjectPtr res, obj;
13815 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013816 xmlLocationSetPtr newlocset = NULL;
13817 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013818 xmlNodeSetPtr oldset;
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013819 xmlNodePtr oldnode = ctxt->context->node;
13820 int oldcs = ctxt->context->contextSize;
13821 int oldpp = ctxt->context->proximityPosition;
William M. Brack72ee48d2003-12-30 08:30:19 +000013822 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013823
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020013824 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013825 total +=
13826 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020013827 CHECK_ERROR0;
13828 }
13829 if (ctxt->value == NULL) {
13830 XP_ERROR0(XPATH_INVALID_OPERAND);
13831 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013832 if (op->ch2 == -1)
13833 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013834
William M. Brack08171912003-12-29 02:52:11 +000013835 if (ctxt->value->type == XPATH_LOCATIONSET) {
13836 /*
13837 * Extract the old locset, and then evaluate the result of the
13838 * expression for all the element in the locset. use it to grow
13839 * up a new locset.
13840 */
13841 CHECK_TYPE0(XPATH_LOCATIONSET);
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013842
13843 if ((ctxt->value->user == NULL) ||
13844 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13845 return (total);
13846
William M. Brack08171912003-12-29 02:52:11 +000013847 obj = valuePop(ctxt);
13848 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013849
William M. Brack08171912003-12-29 02:52:11 +000013850 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013851
William M. Brack08171912003-12-29 02:52:11 +000013852 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013853 /*
William M. Brack08171912003-12-29 02:52:11 +000013854 * Run the evaluation with a node list made of a
13855 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013856 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013857 ctxt->context->node = oldlocset->locTab[i]->user;
13858 ctxt->context->contextSize = oldlocset->locNr;
13859 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013860 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13861 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013862 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013863
Daniel Veillardf06307e2001-07-03 10:35:50 +000013864 if (op->ch2 != -1)
13865 total +=
13866 xmlXPathCompOpEval(ctxt,
13867 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013868 if (ctxt->error != XPATH_EXPRESSION_OK) {
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013869 xmlXPtrFreeLocationSet(newlocset);
13870 goto rangeto_error;
William M. Brack2c19a7b2005-04-10 01:03:23 +000013871 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013872
Daniel Veillardf06307e2001-07-03 10:35:50 +000013873 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013874 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013875 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000013876 (xmlLocationSetPtr)res->user;
13877 for (j=0; j<rloc->locNr; j++) {
13878 range = xmlXPtrNewRange(
13879 oldlocset->locTab[i]->user,
13880 oldlocset->locTab[i]->index,
13881 rloc->locTab[j]->user2,
13882 rloc->locTab[j]->index2);
13883 if (range != NULL) {
13884 xmlXPtrLocationSetAdd(newlocset, range);
13885 }
13886 }
13887 } else {
13888 range = xmlXPtrNewRangeNodeObject(
13889 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13890 if (range != NULL) {
13891 xmlXPtrLocationSetAdd(newlocset,range);
13892 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013893 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013894
Daniel Veillardf06307e2001-07-03 10:35:50 +000013895 /*
13896 * Cleanup
13897 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013898 if (res != NULL) {
13899 xmlXPathReleaseObject(ctxt->context, res);
13900 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013901 if (ctxt->value == tmp) {
13902 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013903 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013904 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013905 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013906 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013907 CHECK_TYPE0(XPATH_NODESET);
13908 obj = valuePop(ctxt);
13909 oldset = obj->nodesetval;
William M. Brack08171912003-12-29 02:52:11 +000013910
13911 newlocset = xmlXPtrLocationSetCreate(NULL);
13912
13913 if (oldset != NULL) {
13914 for (i = 0; i < oldset->nodeNr; i++) {
13915 /*
13916 * Run the evaluation with a node list made of a single item
13917 * in the nodeset.
13918 */
13919 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013920 /*
13921 * OPTIMIZE TODO: Avoid recreation for every iteration.
13922 */
13923 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13924 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013925 valuePush(ctxt, tmp);
13926
13927 if (op->ch2 != -1)
13928 total +=
13929 xmlXPathCompOpEval(ctxt,
13930 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013931 if (ctxt->error != XPATH_EXPRESSION_OK) {
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013932 xmlXPtrFreeLocationSet(newlocset);
13933 goto rangeto_error;
William M. Brack2c19a7b2005-04-10 01:03:23 +000013934 }
William M. Brack08171912003-12-29 02:52:11 +000013935
William M. Brack08171912003-12-29 02:52:11 +000013936 res = valuePop(ctxt);
13937 range =
13938 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13939 res);
13940 if (range != NULL) {
13941 xmlXPtrLocationSetAdd(newlocset, range);
13942 }
13943
13944 /*
13945 * Cleanup
13946 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013947 if (res != NULL) {
13948 xmlXPathReleaseObject(ctxt->context, res);
13949 }
William M. Brack08171912003-12-29 02:52:11 +000013950 if (ctxt->value == tmp) {
13951 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013952 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013953 }
William M. Brack08171912003-12-29 02:52:11 +000013954 }
13955 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013956 }
13957
13958 /*
13959 * The result is used as the new evaluation set.
13960 */
William M. Brack08171912003-12-29 02:52:11 +000013961 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Elliott Hughes7fbecab2019-01-10 16:42:03 -080013962rangeto_error:
13963 xmlXPathReleaseObject(ctxt->context, obj);
13964 ctxt->context->node = oldnode;
13965 ctxt->context->contextSize = oldcs;
13966 ctxt->context->proximityPosition = oldpp;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013967 return (total);
13968 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013969#endif /* LIBXML_XPTR_ENABLED */
13970 }
13971 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013972 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013973 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013974 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013975}
13976
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013977/**
13978 * xmlXPathCompOpEvalToBoolean:
13979 * @ctxt: the XPath parser context
13980 *
13981 * Evaluates if the expression evaluates to true.
13982 *
13983 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13984 */
13985static int
13986xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013987 xmlXPathStepOpPtr op,
13988 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013989{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013990 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013991
13992start:
13993 /* comp = ctxt->comp; */
13994 switch (op->op) {
13995 case XPATH_OP_END:
13996 return (0);
13997 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013998 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013999 if (isPredicate)
14000 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14001 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014002 case XPATH_OP_SORT:
14003 /*
14004 * We don't need sorting for boolean results. Skip this one.
14005 */
14006 if (op->ch1 != -1) {
14007 op = &ctxt->comp->steps[op->ch1];
14008 goto start;
14009 }
14010 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014011 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014012 if (op->ch1 == -1)
14013 return(0);
14014
14015 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14016 if (ctxt->error != XPATH_EXPRESSION_OK)
14017 return(-1);
14018
14019 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14020 if (ctxt->error != XPATH_EXPRESSION_OK)
14021 return(-1);
14022
14023 resObj = valuePop(ctxt);
14024 if (resObj == NULL)
14025 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014026 break;
14027 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014028 /*
14029 * Fallback to call xmlXPathCompOpEval().
14030 */
14031 xmlXPathCompOpEval(ctxt, op);
14032 if (ctxt->error != XPATH_EXPRESSION_OK)
14033 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014034
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014035 resObj = valuePop(ctxt);
14036 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014037 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014038 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014039 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014040
14041 if (resObj) {
14042 int res;
14043
14044 if (resObj->type == XPATH_BOOLEAN) {
14045 res = resObj->boolval;
14046 } else if (isPredicate) {
14047 /*
14048 * For predicates a result of type "number" is handled
14049 * differently:
14050 * SPEC XPath 1.0:
14051 * "If the result is a number, the result will be converted
14052 * to true if the number is equal to the context position
14053 * and will be converted to false otherwise;"
14054 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014055 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014056 } else {
14057 res = xmlXPathCastToBoolean(resObj);
14058 }
14059 xmlXPathReleaseObject(ctxt->context, resObj);
14060 return(res);
14061 }
14062
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014063 return(0);
14064}
14065
Daniel Veillard56de87e2005-02-16 00:22:29 +000014066#ifdef XPATH_STREAMING
14067/**
14068 * xmlXPathRunStreamEval:
14069 * @ctxt: the XPath parser context with the compiled expression
14070 *
14071 * Evaluate the Precompiled Streamable XPath expression in the given context.
14072 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014073static int
14074xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14075 xmlXPathObjectPtr *resultSeq, int toBool)
14076{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014077 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014078 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014079 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014080 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014081 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014082 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014083
14084 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014085
14086 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014087 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014088 max_depth = xmlPatternMaxDepth(comp);
14089 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014090 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014091 if (max_depth == -2)
14092 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014093 min_depth = xmlPatternMinDepth(comp);
14094 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014095 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014096 from_root = xmlPatternFromRoot(comp);
14097 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014098 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014099#if 0
14100 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14101#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014102
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014103 if (! toBool) {
14104 if (resultSeq == NULL)
14105 return(-1);
14106 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14107 if (*resultSeq == NULL)
14108 return(-1);
14109 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014110
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014111 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014112 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014113 */
14114 if (min_depth == 0) {
14115 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014116 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014117 if (toBool)
14118 return(1);
14119 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014120 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014121 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014122 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014123 if (toBool)
14124 return(1);
14125 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014126 }
14127 }
14128 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014129 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014130 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014131
Daniel Veillard56de87e2005-02-16 00:22:29 +000014132 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014133 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014134 } else if (ctxt->node != NULL) {
14135 switch (ctxt->node->type) {
14136 case XML_ELEMENT_NODE:
14137 case XML_DOCUMENT_NODE:
14138 case XML_DOCUMENT_FRAG_NODE:
14139 case XML_HTML_DOCUMENT_NODE:
14140#ifdef LIBXML_DOCB_ENABLED
14141 case XML_DOCB_DOCUMENT_NODE:
14142#endif
14143 cur = ctxt->node;
14144 break;
14145 case XML_ATTRIBUTE_NODE:
14146 case XML_TEXT_NODE:
14147 case XML_CDATA_SECTION_NODE:
14148 case XML_ENTITY_REF_NODE:
14149 case XML_ENTITY_NODE:
14150 case XML_PI_NODE:
14151 case XML_COMMENT_NODE:
14152 case XML_NOTATION_NODE:
14153 case XML_DTD_NODE:
14154 case XML_DOCUMENT_TYPE_NODE:
14155 case XML_ELEMENT_DECL:
14156 case XML_ATTRIBUTE_DECL:
14157 case XML_ENTITY_DECL:
14158 case XML_NAMESPACE_DECL:
14159 case XML_XINCLUDE_START:
14160 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014161 break;
14162 }
14163 limit = cur;
14164 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014165 if (cur == NULL) {
14166 return(0);
14167 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014168
14169 patstream = xmlPatternGetStreamCtxt(comp);
14170 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014171 /*
14172 * QUESTION TODO: Is this an error?
14173 */
14174 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014175 }
14176
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014177 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014178
Daniel Veillard56de87e2005-02-16 00:22:29 +000014179 if (from_root) {
14180 ret = xmlStreamPush(patstream, NULL, NULL);
14181 if (ret < 0) {
14182 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014183 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014184 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014185 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014186 }
14187 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014188 depth = 0;
14189 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014190next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014191 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014192 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014193
14194 switch (cur->type) {
14195 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014196 case XML_TEXT_NODE:
14197 case XML_CDATA_SECTION_NODE:
14198 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014199 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014200 if (cur->type == XML_ELEMENT_NODE) {
14201 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014202 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014203 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014204 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14205 else
14206 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014207
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014208 if (ret < 0) {
14209 /* NOP. */
14210 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014211 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014212 goto return_1;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014213 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14214 < 0) {
14215 ctxt->lastError.domain = XML_FROM_XPATH;
14216 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14217 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014218 }
14219 if ((cur->children == NULL) || (depth >= max_depth)) {
14220 ret = xmlStreamPop(patstream);
14221 while (cur->next != NULL) {
14222 cur = cur->next;
14223 if ((cur->type != XML_ENTITY_DECL) &&
14224 (cur->type != XML_DTD_NODE))
14225 goto next_node;
14226 }
14227 }
14228 default:
14229 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014230 }
14231
Daniel Veillard56de87e2005-02-16 00:22:29 +000014232scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080014233 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014234 if ((cur->children != NULL) && (depth < max_depth)) {
14235 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014236 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014237 */
14238 if (cur->children->type != XML_ENTITY_DECL) {
14239 cur = cur->children;
14240 depth++;
14241 /*
14242 * Skip DTDs
14243 */
14244 if (cur->type != XML_DTD_NODE)
14245 continue;
14246 }
14247 }
14248
14249 if (cur == limit)
14250 break;
14251
14252 while (cur->next != NULL) {
14253 cur = cur->next;
14254 if ((cur->type != XML_ENTITY_DECL) &&
14255 (cur->type != XML_DTD_NODE))
14256 goto next_node;
14257 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014258
Daniel Veillard56de87e2005-02-16 00:22:29 +000014259 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014260 cur = cur->parent;
14261 depth--;
14262 if ((cur == NULL) || (cur == limit))
14263 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014264 if (cur->type == XML_ELEMENT_NODE) {
14265 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014266 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014267 ((cur->type == XML_TEXT_NODE) ||
14268 (cur->type == XML_CDATA_SECTION_NODE) ||
14269 (cur->type == XML_COMMENT_NODE) ||
14270 (cur->type == XML_PI_NODE)))
14271 {
14272 ret = xmlStreamPop(patstream);
14273 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014274 if (cur->next != NULL) {
14275 cur = cur->next;
14276 break;
14277 }
14278 } while (cur != NULL);
14279
14280 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014281
Daniel Veillard56de87e2005-02-16 00:22:29 +000014282done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014283
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014284#if 0
14285 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014286 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014287#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014288
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014289 if (patstream)
14290 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014291 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014292
14293return_1:
14294 if (patstream)
14295 xmlFreeStreamCtxt(patstream);
14296 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014297}
14298#endif /* XPATH_STREAMING */
14299
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014300/**
14301 * xmlXPathRunEval:
14302 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014303 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014304 *
14305 * Evaluate the Precompiled XPath expression in the given context.
14306 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014307static int
14308xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14309{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014310 xmlXPathCompExprPtr comp;
14311
14312 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014313 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014314
14315 if (ctxt->valueTab == NULL) {
14316 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014317 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014318 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14319 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014320 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014321 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014322 }
14323 ctxt->valueNr = 0;
14324 ctxt->valueMax = 10;
14325 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014326 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014327 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014328#ifdef XPATH_STREAMING
14329 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014330 int res;
14331
14332 if (toBool) {
14333 /*
14334 * Evaluation to boolean result.
14335 */
14336 res = xmlXPathRunStreamEval(ctxt->context,
14337 ctxt->comp->stream, NULL, 1);
14338 if (res != -1)
14339 return(res);
14340 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014341 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014342
14343 /*
14344 * Evaluation to a sequence.
14345 */
14346 res = xmlXPathRunStreamEval(ctxt->context,
14347 ctxt->comp->stream, &resObj, 0);
14348
14349 if ((res != -1) && (resObj != NULL)) {
14350 valuePush(ctxt, resObj);
14351 return(0);
14352 }
14353 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014354 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014355 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014356 /*
14357 * QUESTION TODO: This falls back to normal XPath evaluation
14358 * if res == -1. Is this intended?
14359 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014360 }
14361#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014362 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014363 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014364 xmlGenericError(xmlGenericErrorContext,
14365 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014366 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014367 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014368 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014369 return(xmlXPathCompOpEvalToBoolean(ctxt,
14370 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014371 else
14372 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14373
14374 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014375}
14376
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014377/************************************************************************
14378 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014379 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014380 * *
14381 ************************************************************************/
14382
14383/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014384 * xmlXPathEvalPredicate:
14385 * @ctxt: the XPath context
14386 * @res: the Predicate Expression evaluation result
14387 *
14388 * Evaluate a predicate result for the current node.
14389 * A PredicateExpr is evaluated by evaluating the Expr and converting
14390 * the result to a boolean. If the result is a number, the result will
14391 * be converted to true if the number is equal to the position of the
14392 * context node in the context node list (as returned by the position
14393 * function) and will be converted to false otherwise; if the result
14394 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014395 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014396 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014397 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014398 */
14399int
14400xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014401 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014402 switch (res->type) {
14403 case XPATH_BOOLEAN:
14404 return(res->boolval);
14405 case XPATH_NUMBER:
14406 return(res->floatval == ctxt->proximityPosition);
14407 case XPATH_NODESET:
14408 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014409 if (res->nodesetval == NULL)
14410 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014411 return(res->nodesetval->nodeNr != 0);
14412 case XPATH_STRING:
14413 return((res->stringval != NULL) &&
14414 (xmlStrlen(res->stringval) != 0));
14415 default:
14416 STRANGE
14417 }
14418 return(0);
14419}
14420
14421/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014422 * xmlXPathEvaluatePredicateResult:
14423 * @ctxt: the XPath Parser context
14424 * @res: the Predicate Expression evaluation result
14425 *
14426 * Evaluate a predicate result for the current node.
14427 * A PredicateExpr is evaluated by evaluating the Expr and converting
14428 * the result to a boolean. If the result is a number, the result will
14429 * be converted to true if the number is equal to the position of the
14430 * context node in the context node list (as returned by the position
14431 * function) and will be converted to false otherwise; if the result
14432 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014433 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014434 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014435 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014436 */
14437int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014438xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014439 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014440 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014441 switch (res->type) {
14442 case XPATH_BOOLEAN:
14443 return(res->boolval);
14444 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014445#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014446 return((res->floatval == ctxt->context->proximityPosition) &&
14447 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014448#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014449 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014450#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014451 case XPATH_NODESET:
14452 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014453 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014454 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014455 return(res->nodesetval->nodeNr != 0);
14456 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014457 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014458#ifdef LIBXML_XPTR_ENABLED
14459 case XPATH_LOCATIONSET:{
14460 xmlLocationSetPtr ptr = res->user;
14461 if (ptr == NULL)
14462 return(0);
14463 return (ptr->locNr != 0);
14464 }
14465#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014466 default:
14467 STRANGE
14468 }
14469 return(0);
14470}
14471
Daniel Veillard56de87e2005-02-16 00:22:29 +000014472#ifdef XPATH_STREAMING
14473/**
14474 * xmlXPathTryStreamCompile:
14475 * @ctxt: an XPath context
14476 * @str: the XPath expression
14477 *
14478 * Try to compile the XPath expression as a streamable subset.
14479 *
14480 * Returns the compiled expression or NULL if failed to compile.
14481 */
14482static xmlXPathCompExprPtr
14483xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14484 /*
14485 * Optimization: use streaming patterns when the XPath expression can
14486 * be compiled to a stream lookup
14487 */
14488 xmlPatternPtr stream;
14489 xmlXPathCompExprPtr comp;
14490 xmlDictPtr dict = NULL;
14491 const xmlChar **namespaces = NULL;
14492 xmlNsPtr ns;
14493 int i, j;
14494
14495 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14496 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014497 const xmlChar *tmp;
14498
14499 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014500 * We don't try to handle expressions using the verbose axis
14501 * specifiers ("::"), just the simplied form at this point.
14502 * Additionally, if there is no list of namespaces available and
14503 * there's a ":" in the expression, indicating a prefixed QName,
14504 * then we won't try to compile either. xmlPatterncompile() needs
14505 * to have a list of namespaces at compilation time in order to
14506 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014507 */
14508 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014509 if ((tmp != NULL) &&
14510 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014511 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014512
Daniel Veillard56de87e2005-02-16 00:22:29 +000014513 if (ctxt != NULL) {
14514 dict = ctxt->dict;
14515 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014516 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014517 if (namespaces == NULL) {
14518 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14519 return(NULL);
14520 }
14521 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14522 ns = ctxt->namespaces[j];
14523 namespaces[i++] = ns->href;
14524 namespaces[i++] = ns->prefix;
14525 }
14526 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014527 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014528 }
14529 }
14530
William M. Brackea152c02005-06-09 18:12:28 +000014531 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14532 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014533 if (namespaces != NULL) {
14534 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014535 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014536 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14537 comp = xmlXPathNewCompExpr();
14538 if (comp == NULL) {
14539 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14540 return(NULL);
14541 }
14542 comp->stream = stream;
14543 comp->dict = dict;
14544 if (comp->dict)
14545 xmlDictReference(comp->dict);
14546 return(comp);
14547 }
14548 xmlFreePattern(stream);
14549 }
14550 return(NULL);
14551}
14552#endif /* XPATH_STREAMING */
14553
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014554static void
Nick Wellnhofer62270532012-08-19 19:42:38 +020014555xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014556{
14557 /*
14558 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14559 * internal representation.
14560 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014561
Nick Wellnhoferb4bcba22013-08-05 00:15:11 +020014562 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14563 (op->ch1 != -1) &&
14564 (op->ch2 == -1 /* no predicate */))
Nick Wellnhofer62270532012-08-19 19:42:38 +020014565 {
14566 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14567
14568 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14569 ((xmlXPathAxisVal) prevop->value ==
14570 AXIS_DESCENDANT_OR_SELF) &&
14571 (prevop->ch2 == -1) &&
14572 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14573 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14574 {
14575 /*
14576 * This is a "descendant-or-self::node()" without predicates.
14577 * Try to eliminate it.
14578 */
14579
14580 switch ((xmlXPathAxisVal) op->value) {
14581 case AXIS_CHILD:
14582 case AXIS_DESCENDANT:
14583 /*
14584 * Convert "descendant-or-self::node()/child::" or
14585 * "descendant-or-self::node()/descendant::" to
14586 * "descendant::"
14587 */
14588 op->ch1 = prevop->ch1;
14589 op->value = AXIS_DESCENDANT;
14590 break;
14591 case AXIS_SELF:
14592 case AXIS_DESCENDANT_OR_SELF:
14593 /*
14594 * Convert "descendant-or-self::node()/self::" or
14595 * "descendant-or-self::node()/descendant-or-self::" to
14596 * to "descendant-or-self::"
14597 */
14598 op->ch1 = prevop->ch1;
14599 op->value = AXIS_DESCENDANT_OR_SELF;
14600 break;
14601 default:
14602 break;
14603 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014604 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014605 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014606
Nick Wellnhofer839689a2016-04-27 18:00:12 +020014607 /* OP_VALUE has invalid ch1. */
14608 if (op->op == XPATH_OP_VALUE)
14609 return;
14610
Nick Wellnhofer62270532012-08-19 19:42:38 +020014611 /* Recurse */
14612 if (op->ch1 != -1)
14613 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014614 if (op->ch2 != -1)
Nick Wellnhofer62270532012-08-19 19:42:38 +020014615 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014616}
14617
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014618/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014619 * xmlXPathCtxtCompile:
14620 * @ctxt: an XPath context
14621 * @str: the XPath expression
14622 *
14623 * Compile an XPath expression
14624 *
14625 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14626 * the caller has to free the object.
14627 */
14628xmlXPathCompExprPtr
14629xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14630 xmlXPathParserContextPtr pctxt;
14631 xmlXPathCompExprPtr comp;
14632
Daniel Veillard56de87e2005-02-16 00:22:29 +000014633#ifdef XPATH_STREAMING
14634 comp = xmlXPathTryStreamCompile(ctxt, str);
14635 if (comp != NULL)
14636 return(comp);
14637#endif
14638
Daniel Veillard4773df22004-01-23 13:15:13 +000014639 xmlXPathInit();
14640
14641 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014642 if (pctxt == NULL)
14643 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014644 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014645
14646 if( pctxt->error != XPATH_EXPRESSION_OK )
14647 {
14648 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014649 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014650 }
14651
14652 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014653 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014654 * aleksey: in some cases this line prints *second* error message
14655 * (see bug #78858) and probably this should be fixed.
14656 * However, we are not sure that all error messages are printed
14657 * out in other places. It's not critical so we leave it as-is for now
14658 */
14659 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14660 comp = NULL;
14661 } else {
14662 comp = pctxt->comp;
14663 pctxt->comp = NULL;
14664 }
14665 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014666
Daniel Veillard4773df22004-01-23 13:15:13 +000014667 if (comp != NULL) {
14668 comp->expr = xmlStrdup(str);
14669#ifdef DEBUG_EVAL_COUNTS
14670 comp->string = xmlStrdup(str);
14671 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014672#endif
Nick Wellnhofer62270532012-08-19 19:42:38 +020014673 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14674 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014675 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014676 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014677 return(comp);
14678}
14679
14680/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014681 * xmlXPathCompile:
14682 * @str: the XPath expression
14683 *
14684 * Compile an XPath expression
14685 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014686 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014687 * the caller has to free the object.
14688 */
14689xmlXPathCompExprPtr
14690xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014691 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014692}
14693
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014694/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014695 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014696 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014697 * @ctxt: the XPath context
14698 * @resObj: the resulting XPath object or NULL
14699 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014700 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014701 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014702 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014703 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014704 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014705 * the caller has to free the object.
14706 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014707static int
14708xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14709 xmlXPathContextPtr ctxt,
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014710 xmlXPathObjectPtr *resObjPtr,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014711 int toBool)
14712{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014713 xmlXPathParserContextPtr pctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014714 xmlXPathObjectPtr resObj;
Daniel Veillard81463942001-10-16 12:34:39 +000014715#ifndef LIBXML_THREAD_ENABLED
14716 static int reentance = 0;
14717#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014718 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014719
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014720 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014721
14722 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014723 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014724 xmlXPathInit();
14725
Daniel Veillard81463942001-10-16 12:34:39 +000014726#ifndef LIBXML_THREAD_ENABLED
14727 reentance++;
14728 if (reentance > 1)
14729 xmlXPathDisableOptimizer = 1;
14730#endif
14731
Daniel Veillardf06307e2001-07-03 10:35:50 +000014732#ifdef DEBUG_EVAL_COUNTS
14733 comp->nb++;
14734 if ((comp->string != NULL) && (comp->nb > 100)) {
14735 fprintf(stderr, "100 x %s\n", comp->string);
14736 comp->nb = 0;
14737 }
14738#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014739 pctxt = xmlXPathCompParserContext(comp, ctxt);
14740 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014741
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014742 if (pctxt->error != XPATH_EXPRESSION_OK) {
14743 resObj = NULL;
14744 } else {
14745 resObj = valuePop(pctxt);
14746 if (resObj == NULL) {
Nick Wellnhofera07a4e92017-05-27 17:04:12 +020014747 if (!toBool)
14748 xmlGenericError(xmlGenericErrorContext,
14749 "xmlXPathCompiledEval: No result on the stack.\n");
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014750 } else if (pctxt->valueNr > 0) {
14751 xmlGenericError(xmlGenericErrorContext,
14752 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14753 pctxt->valueNr);
14754 }
Owen Taylor3473f882001-02-23 17:55:21 +000014755 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014756
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014757 if (resObjPtr)
14758 *resObjPtr = resObj;
14759 else
14760 xmlXPathReleaseObject(ctxt, resObj);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014761
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014762 pctxt->comp = NULL;
14763 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014764#ifndef LIBXML_THREAD_ENABLED
14765 reentance--;
14766#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014767
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014768 return(res);
14769}
14770
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014771/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014772 * xmlXPathCompiledEval:
14773 * @comp: the compiled XPath expression
14774 * @ctx: the XPath context
14775 *
14776 * Evaluate the Precompiled XPath expression in the given context.
14777 *
14778 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14779 * the caller has to free the object.
14780 */
14781xmlXPathObjectPtr
14782xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14783{
14784 xmlXPathObjectPtr res = NULL;
14785
14786 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14787 return(res);
14788}
14789
14790/**
14791 * xmlXPathCompiledEvalToBoolean:
14792 * @comp: the compiled XPath expression
14793 * @ctxt: the XPath context
14794 *
14795 * Applies the XPath boolean() function on the result of the given
14796 * compiled expression.
14797 *
14798 * Returns 1 if the expression evaluated to true, 0 if to false and
14799 * -1 in API and internal errors.
14800 */
14801int
14802xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14803 xmlXPathContextPtr ctxt)
14804{
14805 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14806}
14807
14808/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014809 * xmlXPathEvalExpr:
14810 * @ctxt: the XPath Parser context
14811 *
14812 * Parse and evaluate an XPath expression in the given context,
14813 * then push the result on the context stack
14814 */
14815void
14816xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014817#ifdef XPATH_STREAMING
14818 xmlXPathCompExprPtr comp;
14819#endif
14820
Daniel Veillarda82b1822004-11-08 16:24:57 +000014821 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014822
Daniel Veillard56de87e2005-02-16 00:22:29 +000014823#ifdef XPATH_STREAMING
14824 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14825 if (comp != NULL) {
14826 if (ctxt->comp != NULL)
14827 xmlXPathFreeCompExpr(ctxt->comp);
14828 ctxt->comp = comp;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014829 } else
14830#endif
14831 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014832 xmlXPathCompileExpr(ctxt, 1);
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020014833 CHECK_ERROR;
14834
14835 /* Check for trailing characters. */
14836 if (*ctxt->cur != 0)
14837 XP_ERROR(XPATH_EXPR_ERROR);
14838
14839 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
Nick Wellnhofer62270532012-08-19 19:42:38 +020014840 xmlXPathOptimizeExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014841 &ctxt->comp->steps[ctxt->comp->last]);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014842 }
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020014843
Daniel Veillard45490ae2008-07-29 09:13:19 +000014844 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014845}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014846
14847/**
14848 * xmlXPathEval:
14849 * @str: the XPath expression
14850 * @ctx: the XPath context
14851 *
14852 * Evaluate the XPath Location Path in the given context.
14853 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014854 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014855 * the caller has to free the object.
14856 */
14857xmlXPathObjectPtr
14858xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14859 xmlXPathParserContextPtr ctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014860 xmlXPathObjectPtr res;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014861
William M. Brackf13f77f2004-11-12 16:03:48 +000014862 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014863
William M. Brackf13f77f2004-11-12 16:03:48 +000014864 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014865
14866 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014867 if (ctxt == NULL)
14868 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014869 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014870
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014871 if (ctxt->error != XPATH_EXPRESSION_OK) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014872 res = NULL;
14873 } else {
14874 res = valuePop(ctxt);
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014875 if (res == NULL) {
14876 xmlGenericError(xmlGenericErrorContext,
14877 "xmlXPathCompiledEval: No result on the stack.\n");
14878 } else if (ctxt->valueNr > 0) {
14879 xmlGenericError(xmlGenericErrorContext,
14880 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14881 ctxt->valueNr);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014882 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014883 }
14884
Owen Taylor3473f882001-02-23 17:55:21 +000014885 xmlXPathFreeParserContext(ctxt);
14886 return(res);
14887}
14888
14889/**
Alex Bligh28876af2013-03-23 17:23:27 +000014890 * xmlXPathSetContextNode:
14891 * @node: the node to to use as the context node
14892 * @ctx: the XPath context
14893 *
14894 * Sets 'node' as the context node. The node must be in the same
14895 * document as that associated with the context.
14896 *
14897 * Returns -1 in case of error or 0 if successful
14898 */
14899int
14900xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14901 if ((node == NULL) || (ctx == NULL))
14902 return(-1);
14903
14904 if (node->doc == ctx->doc) {
14905 ctx->node = node;
14906 return(0);
14907 }
14908 return(-1);
14909}
14910
14911/**
14912 * xmlXPathNodeEval:
14913 * @node: the node to to use as the context node
14914 * @str: the XPath expression
14915 * @ctx: the XPath context
14916 *
14917 * Evaluate the XPath Location Path in the given context. The node 'node'
14918 * is set as the context node. The context node is not restored.
14919 *
14920 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14921 * the caller has to free the object.
14922 */
14923xmlXPathObjectPtr
14924xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14925 if (str == NULL)
14926 return(NULL);
14927 if (xmlXPathSetContextNode(node, ctx) < 0)
14928 return(NULL);
14929 return(xmlXPathEval(str, ctx));
14930}
14931
14932/**
Owen Taylor3473f882001-02-23 17:55:21 +000014933 * xmlXPathEvalExpression:
14934 * @str: the XPath expression
14935 * @ctxt: the XPath context
14936 *
Daniel Veillarddbb828f2017-08-28 20:38:53 +020014937 * Alias for xmlXPathEval().
Owen Taylor3473f882001-02-23 17:55:21 +000014938 *
14939 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14940 * the caller has to free the object.
14941 */
14942xmlXPathObjectPtr
14943xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Nick Wellnhofer640a3682017-05-27 14:59:49 +020014944 return(xmlXPathEval(str, ctxt));
Owen Taylor3473f882001-02-23 17:55:21 +000014945}
14946
Daniel Veillard42766c02002-08-22 20:52:17 +000014947/************************************************************************
14948 * *
14949 * Extra functions not pertaining to the XPath spec *
14950 * *
14951 ************************************************************************/
14952/**
14953 * xmlXPathEscapeUriFunction:
14954 * @ctxt: the XPath Parser context
14955 * @nargs: the number of arguments
14956 *
14957 * Implement the escape-uri() XPath function
14958 * string escape-uri(string $str, bool $escape-reserved)
14959 *
14960 * This function applies the URI escaping rules defined in section 2 of [RFC
14961 * 2396] to the string supplied as $uri-part, which typically represents all
14962 * or part of a URI. The effect of the function is to replace any special
14963 * character in the string by an escape sequence of the form %xx%yy...,
14964 * where xxyy... is the hexadecimal representation of the octets used to
14965 * represent the character in UTF-8.
14966 *
14967 * The set of characters that are escaped depends on the setting of the
14968 * boolean argument $escape-reserved.
14969 *
14970 * If $escape-reserved is true, all characters are escaped other than lower
14971 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14972 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14973 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14974 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14975 * A-F).
14976 *
14977 * If $escape-reserved is false, the behavior differs in that characters
14978 * referred to in [RFC 2396] as reserved characters are not escaped. These
14979 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000014980 *
Daniel Veillard42766c02002-08-22 20:52:17 +000014981 * [RFC 2396] does not define whether escaped URIs should use lower case or
14982 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14983 * compared using string comparison functions, this function must always use
14984 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000014985 *
Daniel Veillard42766c02002-08-22 20:52:17 +000014986 * Generally, $escape-reserved should be set to true when escaping a string
14987 * that is to form a single part of a URI, and to false when escaping an
14988 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000014989 *
14990 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000014991 * utf-8 and then converted according to RFC 2396.
14992 *
14993 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000014994 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000014995 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14996 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14997 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14998 *
14999 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015000static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015001xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15002 xmlXPathObjectPtr str;
15003 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080015004 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000015005 xmlChar *cptr;
15006 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015007
Daniel Veillard42766c02002-08-22 20:52:17 +000015008 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015009
Daniel Veillard42766c02002-08-22 20:52:17 +000015010 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015011
Daniel Veillard42766c02002-08-22 20:52:17 +000015012 CAST_TO_STRING;
15013 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015014
Daniel Veillardade10f22012-07-12 09:43:27 +080015015 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015016
Daniel Veillard42766c02002-08-22 20:52:17 +000015017 escape[0] = '%';
15018 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015019
Daniel Veillard42766c02002-08-22 20:52:17 +000015020 if (target) {
15021 for (cptr = str->stringval; *cptr; cptr++) {
15022 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15023 (*cptr >= 'a' && *cptr <= 'z') ||
15024 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015025 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015026 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15027 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015028 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015029 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15030 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15031 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15032 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15033 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15034 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15035 (!escape_reserved &&
15036 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15037 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15038 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15039 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080015040 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000015041 } else {
15042 if ((*cptr >> 4) < 10)
15043 escape[1] = '0' + (*cptr >> 4);
15044 else
15045 escape[1] = 'A' - 10 + (*cptr >> 4);
15046 if ((*cptr & 0xF) < 10)
15047 escape[2] = '0' + (*cptr & 0xF);
15048 else
15049 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015050
Daniel Veillardade10f22012-07-12 09:43:27 +080015051 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000015052 }
15053 }
15054 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015055 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080015056 xmlBufContent(target)));
15057 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015058 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015059}
15060
Owen Taylor3473f882001-02-23 17:55:21 +000015061/**
15062 * xmlXPathRegisterAllFunctions:
15063 * @ctxt: the XPath context
15064 *
15065 * Registers all default XPath functions in this context
15066 */
15067void
15068xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15069{
15070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15071 xmlXPathBooleanFunction);
15072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15073 xmlXPathCeilingFunction);
15074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15075 xmlXPathCountFunction);
15076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15077 xmlXPathConcatFunction);
15078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15079 xmlXPathContainsFunction);
15080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15081 xmlXPathIdFunction);
15082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15083 xmlXPathFalseFunction);
15084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15085 xmlXPathFloorFunction);
15086 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15087 xmlXPathLastFunction);
15088 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15089 xmlXPathLangFunction);
15090 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15091 xmlXPathLocalNameFunction);
15092 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15093 xmlXPathNotFunction);
15094 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15095 xmlXPathNameFunction);
15096 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15097 xmlXPathNamespaceURIFunction);
15098 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15099 xmlXPathNormalizeFunction);
15100 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15101 xmlXPathNumberFunction);
15102 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15103 xmlXPathPositionFunction);
15104 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15105 xmlXPathRoundFunction);
15106 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15107 xmlXPathStringFunction);
15108 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15109 xmlXPathStringLengthFunction);
15110 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15111 xmlXPathStartsWithFunction);
15112 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15113 xmlXPathSubstringFunction);
15114 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15115 xmlXPathSubstringBeforeFunction);
15116 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15117 xmlXPathSubstringAfterFunction);
15118 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15119 xmlXPathSumFunction);
15120 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15121 xmlXPathTrueFunction);
15122 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15123 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015124
15125 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15126 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15127 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015128}
15129
15130#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015131#define bottom_xpath
15132#include "elfgcchack.h"