blob: 2c1b2681bec9a1b9c4101560760d2a57eb075efb [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005 *f
Owen Taylor3473f882001-02-23 17:55:21 +00006 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Stéphane Michaut454e3972017-08-28 14:30:43 +020017/* To avoid EBCDIC trouble when parsing on zOS */
18#if defined(__MVS__)
19#pragma convert("ISO8859-1")
20#endif
21
Daniel Veillard34ce8be2002-03-18 19:37:11 +000022#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000023#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000024
Nick Wellnhofera58331a2017-05-29 21:02:21 +020025#include <limits.h>
Owen Taylor3473f882001-02-23 17:55:21 +000026#include <string.h>
27
28#ifdef HAVE_SYS_TYPES_H
29#include <sys/types.h>
30#endif
31#ifdef HAVE_MATH_H
32#include <math.h>
33#endif
34#ifdef HAVE_FLOAT_H
35#include <float.h>
36#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037#ifdef HAVE_CTYPE_H
38#include <ctype.h>
39#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000040#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000041#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000042#endif
Owen Taylor3473f882001-02-23 17:55:21 +000043
44#include <libxml/xmlmemory.h>
45#include <libxml/tree.h>
46#include <libxml/valid.h>
47#include <libxml/xpath.h>
48#include <libxml/xpathInternals.h>
49#include <libxml/parserInternals.h>
50#include <libxml/hash.h>
51#ifdef LIBXML_XPTR_ENABLED
52#include <libxml/xpointer.h>
53#endif
54#ifdef LIBXML_DEBUG_ENABLED
55#include <libxml/debugXML.h>
56#endif
57#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000058#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000059#include <libxml/globals.h>
Daniel Veillard56de87e2005-02-16 00:22:29 +000060#ifdef LIBXML_PATTERN_ENABLED
61#include <libxml/pattern.h>
62#endif
63
Daniel Veillardade10f22012-07-12 09:43:27 +080064#include "buf.h"
65
Daniel Veillard56de87e2005-02-16 00:22:29 +000066#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000067#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000068#endif
Owen Taylor3473f882001-02-23 17:55:21 +000069
Daniel Veillard45490ae2008-07-29 09:13:19 +000070#define TODO \
Daniel Veillardd96f6d32003-10-07 21:25:12 +000071 xmlGenericError(xmlGenericErrorContext, \
72 "Unimplemented block at %s:%d\n", \
73 __FILE__, __LINE__);
74
Vojtech Fried3e031b72012-08-24 16:52:44 +080075/**
76 * WITH_TIM_SORT:
77 *
78 * Use the Timsort algorithm provided in timsort.h to sort
79 * nodeset as this is a great improvement over the old Shell sort
80 * used in xmlXPathNodeSetSort()
81 */
82#define WITH_TIM_SORT
83
William M. Brackd1757ab2004-10-02 22:07:48 +000084/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000085* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000086* If defined, this will use xmlXPathCmpNodesExt() instead of
87* xmlXPathCmpNodes(). The new function is optimized comparison of
88* non-element nodes; actually it will speed up comparison only if
89* xmlXPathOrderDocElems() was called in order to index the elements of
90* a tree in document order; Libxslt does such an indexing, thus it will
91* benefit from this optimization.
92*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000093#define XP_OPTIMIZED_NON_ELEM_COMPARISON
94
95/*
96* XP_OPTIMIZED_FILTER_FIRST:
97* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
98* in a way, that it stop evaluation at the first node.
Daniel Veillard45490ae2008-07-29 09:13:19 +000099*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000100#define XP_OPTIMIZED_FILTER_FIRST
101
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000102/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000103* XP_DEBUG_OBJ_USAGE:
104* Internal flag to enable tracking of how much XPath objects have been
105* created.
106*/
107/* #define XP_DEBUG_OBJ_USAGE */
108
109/*
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800110 * XPATH_MAX_STEPS:
111 * when compiling an XPath expression we arbitrary limit the maximum
112 * number of step operation in the compiled expression. 1000000 is
113 * an insanely large value which should never be reached under normal
114 * circumstances
115 */
116#define XPATH_MAX_STEPS 1000000
117
118/*
119 * XPATH_MAX_STACK_DEPTH:
120 * when evaluating an XPath expression we arbitrary limit the maximum
121 * number of object allowed to be pushed on the stack. 1000000 is
122 * an insanely large value which should never be reached under normal
123 * circumstances
124 */
125#define XPATH_MAX_STACK_DEPTH 1000000
126
127/*
128 * XPATH_MAX_NODESET_LENGTH:
129 * when evaluating an XPath expression nodesets are created and we
130 * arbitrary limit the maximum length of those node set. 10000000 is
131 * an insanely large value which should never be reached under normal
132 * circumstances, one would first need to construct an in memory tree
133 * with more than 10 millions nodes.
134 */
135#define XPATH_MAX_NODESET_LENGTH 10000000
136
137/*
William M. Brackd1757ab2004-10-02 22:07:48 +0000138 * TODO:
139 * There are a few spots where some tests are done which depend upon ascii
140 * data. These should be enhanced for full UTF8 support (see particularly
141 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
142 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000143
Denis Pauke28c8a12013-08-03 14:22:54 +0300144#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
145/**
146 * xmlXPathCmpNodesExt:
147 * @node1: the first node
148 * @node2: the second node
149 *
150 * Compare two nodes w.r.t document order.
151 * This one is optimized for handling of non-element nodes.
152 *
153 * Returns -2 in case of error 1 if first point < second point, 0 if
154 * it's the same node, -1 otherwise
155 */
156static int
157xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
158 int depth1, depth2;
159 int misc = 0, precedence1 = 0, precedence2 = 0;
160 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
161 xmlNodePtr cur, root;
162 long l1, l2;
163
164 if ((node1 == NULL) || (node2 == NULL))
165 return(-2);
166
167 if (node1 == node2)
168 return(0);
169
170 /*
171 * a couple of optimizations which will avoid computations in most cases
172 */
173 switch (node1->type) {
174 case XML_ELEMENT_NODE:
175 if (node2->type == XML_ELEMENT_NODE) {
176 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
177 (0 > (long) node2->content) &&
178 (node1->doc == node2->doc))
179 {
180 l1 = -((long) node1->content);
181 l2 = -((long) node2->content);
182 if (l1 < l2)
183 return(1);
184 if (l1 > l2)
185 return(-1);
186 } else
187 goto turtle_comparison;
188 }
189 break;
190 case XML_ATTRIBUTE_NODE:
191 precedence1 = 1; /* element is owner */
192 miscNode1 = node1;
193 node1 = node1->parent;
194 misc = 1;
195 break;
196 case XML_TEXT_NODE:
197 case XML_CDATA_SECTION_NODE:
198 case XML_COMMENT_NODE:
199 case XML_PI_NODE: {
200 miscNode1 = node1;
201 /*
202 * Find nearest element node.
203 */
204 if (node1->prev != NULL) {
205 do {
206 node1 = node1->prev;
207 if (node1->type == XML_ELEMENT_NODE) {
208 precedence1 = 3; /* element in prev-sibl axis */
209 break;
210 }
211 if (node1->prev == NULL) {
212 precedence1 = 2; /* element is parent */
213 /*
214 * URGENT TODO: Are there any cases, where the
215 * parent of such a node is not an element node?
216 */
217 node1 = node1->parent;
218 break;
219 }
220 } while (1);
221 } else {
222 precedence1 = 2; /* element is parent */
223 node1 = node1->parent;
224 }
225 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
226 (0 <= (long) node1->content)) {
227 /*
228 * Fallback for whatever case.
229 */
230 node1 = miscNode1;
231 precedence1 = 0;
232 } else
233 misc = 1;
234 }
235 break;
236 case XML_NAMESPACE_DECL:
237 /*
238 * TODO: why do we return 1 for namespace nodes?
239 */
240 return(1);
241 default:
242 break;
243 }
244 switch (node2->type) {
245 case XML_ELEMENT_NODE:
246 break;
247 case XML_ATTRIBUTE_NODE:
248 precedence2 = 1; /* element is owner */
249 miscNode2 = node2;
250 node2 = node2->parent;
251 misc = 1;
252 break;
253 case XML_TEXT_NODE:
254 case XML_CDATA_SECTION_NODE:
255 case XML_COMMENT_NODE:
256 case XML_PI_NODE: {
257 miscNode2 = node2;
258 if (node2->prev != NULL) {
259 do {
260 node2 = node2->prev;
261 if (node2->type == XML_ELEMENT_NODE) {
262 precedence2 = 3; /* element in prev-sibl axis */
263 break;
264 }
265 if (node2->prev == NULL) {
266 precedence2 = 2; /* element is parent */
267 node2 = node2->parent;
268 break;
269 }
270 } while (1);
271 } else {
272 precedence2 = 2; /* element is parent */
273 node2 = node2->parent;
274 }
275 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
Gauravfcd45832013-11-28 23:01:44 +0800276 (0 <= (long) node2->content))
Denis Pauke28c8a12013-08-03 14:22:54 +0300277 {
278 node2 = miscNode2;
279 precedence2 = 0;
280 } else
281 misc = 1;
282 }
283 break;
284 case XML_NAMESPACE_DECL:
285 return(1);
286 default:
287 break;
288 }
289 if (misc) {
290 if (node1 == node2) {
291 if (precedence1 == precedence2) {
292 /*
293 * The ugly case; but normally there aren't many
294 * adjacent non-element nodes around.
295 */
296 cur = miscNode2->prev;
297 while (cur != NULL) {
298 if (cur == miscNode1)
299 return(1);
300 if (cur->type == XML_ELEMENT_NODE)
301 return(-1);
302 cur = cur->prev;
303 }
304 return (-1);
305 } else {
306 /*
307 * Evaluate based on higher precedence wrt to the element.
308 * TODO: This assumes attributes are sorted before content.
309 * Is this 100% correct?
310 */
311 if (precedence1 < precedence2)
312 return(1);
313 else
314 return(-1);
315 }
316 }
317 /*
318 * Special case: One of the helper-elements is contained by the other.
319 * <foo>
320 * <node2>
321 * <node1>Text-1(precedence1 == 2)</node1>
322 * </node2>
323 * Text-6(precedence2 == 3)
324 * </foo>
325 */
326 if ((precedence2 == 3) && (precedence1 > 1)) {
327 cur = node1->parent;
328 while (cur) {
329 if (cur == node2)
330 return(1);
331 cur = cur->parent;
332 }
333 }
334 if ((precedence1 == 3) && (precedence2 > 1)) {
335 cur = node2->parent;
336 while (cur) {
337 if (cur == node1)
338 return(-1);
339 cur = cur->parent;
340 }
341 }
342 }
343
344 /*
345 * Speedup using document order if availble.
346 */
347 if ((node1->type == XML_ELEMENT_NODE) &&
348 (node2->type == XML_ELEMENT_NODE) &&
349 (0 > (long) node1->content) &&
350 (0 > (long) node2->content) &&
351 (node1->doc == node2->doc)) {
352
353 l1 = -((long) node1->content);
354 l2 = -((long) node2->content);
355 if (l1 < l2)
356 return(1);
357 if (l1 > l2)
358 return(-1);
359 }
360
361turtle_comparison:
362
363 if (node1 == node2->prev)
364 return(1);
365 if (node1 == node2->next)
366 return(-1);
367 /*
368 * compute depth to root
369 */
Nick Wellnhofer3eaedba2015-07-11 14:27:34 +0200370 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
371 if (cur->parent == node1)
Denis Pauke28c8a12013-08-03 14:22:54 +0300372 return(1);
373 depth2++;
374 }
375 root = cur;
Nick Wellnhofer3eaedba2015-07-11 14:27:34 +0200376 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
377 if (cur->parent == node2)
Denis Pauke28c8a12013-08-03 14:22:54 +0300378 return(-1);
379 depth1++;
380 }
381 /*
382 * Distinct document (or distinct entities :-( ) case.
383 */
384 if (root != cur) {
385 return(-2);
386 }
387 /*
388 * get the nearest common ancestor.
389 */
390 while (depth1 > depth2) {
391 depth1--;
392 node1 = node1->parent;
393 }
394 while (depth2 > depth1) {
395 depth2--;
396 node2 = node2->parent;
397 }
398 while (node1->parent != node2->parent) {
399 node1 = node1->parent;
400 node2 = node2->parent;
401 /* should not happen but just in case ... */
402 if ((node1 == NULL) || (node2 == NULL))
403 return(-2);
404 }
405 /*
406 * Find who's first.
407 */
408 if (node1 == node2->prev)
409 return(1);
410 if (node1 == node2->next)
411 return(-1);
412 /*
413 * Speedup using document order if availble.
414 */
415 if ((node1->type == XML_ELEMENT_NODE) &&
416 (node2->type == XML_ELEMENT_NODE) &&
417 (0 > (long) node1->content) &&
418 (0 > (long) node2->content) &&
419 (node1->doc == node2->doc)) {
420
421 l1 = -((long) node1->content);
422 l2 = -((long) node2->content);
423 if (l1 < l2)
424 return(1);
425 if (l1 > l2)
426 return(-1);
427 }
428
429 for (cur = node1->next;cur != NULL;cur = cur->next)
430 if (cur == node2)
431 return(1);
432 return(-1); /* assume there is no sibling list corruption */
433}
434#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
435
Vojtech Fried3e031b72012-08-24 16:52:44 +0800436/*
437 * Wrapper for the Timsort argorithm from timsort.h
438 */
439#ifdef WITH_TIM_SORT
440#define SORT_NAME libxml_domnode
441#define SORT_TYPE xmlNodePtr
442/**
443 * wrap_cmp:
444 * @x: a node
445 * @y: another node
446 *
447 * Comparison function for the Timsort implementation
448 *
Daniel Veillard510e7582012-09-04 11:50:36 +0800449 * Returns -2 in case of error -1 if first point < second point, 0 if
450 * it's the same node, +1 otherwise
Vojtech Fried3e031b72012-08-24 16:52:44 +0800451 */
452static
453int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
454#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Vojtech Fried3e031b72012-08-24 16:52:44 +0800455 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
456 {
457 int res = xmlXPathCmpNodesExt(x, y);
458 return res == -2 ? res : -res;
459 }
460#else
461 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
462 {
463 int res = xmlXPathCmpNodes(x, y);
464 return res == -2 ? res : -res;
465 }
466#endif
467#define SORT_CMP(x, y) (wrap_cmp(x, y))
468#include "timsort.h"
469#endif /* WITH_TIM_SORT */
470
William M. Brack21e4ef22005-01-02 09:53:13 +0000471#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000472
473/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000474 * *
475 * Floating point stuff *
476 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000477 ************************************************************************/
478
Daniel Veillardc0631a62001-09-20 13:56:06 +0000479#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000480#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000481#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000482#include "trionan.c"
483
Owen Taylor3473f882001-02-23 17:55:21 +0000484/*
Owen Taylor3473f882001-02-23 17:55:21 +0000485 * The lack of portability of this section of the libc is annoying !
486 */
487double xmlXPathNAN = 0;
488double xmlXPathPINF = 1;
489double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000490static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000491static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000492
Owen Taylor3473f882001-02-23 17:55:21 +0000493/**
494 * xmlXPathInit:
495 *
496 * Initialize the XPath environment
497 */
498void
499xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000500 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000501
Bjorn Reese45029602001-08-21 09:23:53 +0000502 xmlXPathPINF = trio_pinf();
503 xmlXPathNINF = trio_ninf();
504 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000505 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000506
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000507 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000508}
509
Daniel Veillardcda96922001-08-21 10:56:31 +0000510/**
511 * xmlXPathIsNaN:
512 * @val: a double value
513 *
514 * Provides a portable isnan() function to detect whether a double
515 * is a NotaNumber. Based on trio code
516 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000517 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000518 * Returns 1 if the value is a NaN, 0 otherwise
519 */
520int
521xmlXPathIsNaN(double val) {
522 return(trio_isnan(val));
523}
524
525/**
526 * xmlXPathIsInf:
527 * @val: a double value
528 *
529 * Provides a portable isinf() function to detect whether a double
530 * is a +Infinite or -Infinite. Based on trio code
531 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000532 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000533 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
534 */
535int
536xmlXPathIsInf(double val) {
537 return(trio_isinf(val));
538}
539
Daniel Veillard4432df22003-09-28 18:58:27 +0000540#endif /* SCHEMAS or XPATH */
541#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000542/**
543 * xmlXPathGetSign:
544 * @val: a double value
545 *
546 * Provides a portable function to detect the sign of a double
547 * Modified from trio code
548 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000549 *
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000550 * Returns 1 if the value is Negative, 0 if positive
551 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000552static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000553xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000554 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000555}
556
557
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000558/*
559 * TODO: when compatibility allows remove all "fake node libxslt" strings
560 * the test should just be name[0] = ' '
561 */
Daniel Veillard074f37e2008-09-01 13:38:22 +0000562#ifdef DEBUG_XPATH_EXPRESSION
563#define DEBUG_STEP
564#define DEBUG_EXPR
565#define DEBUG_EVAL_COUNTS
566#endif
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000567
568static xmlNs xmlXPathXMLNamespaceStruct = {
569 NULL,
570 XML_NAMESPACE_DECL,
571 XML_XML_NAMESPACE,
572 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000573 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000574 NULL
575};
576static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
577#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard45490ae2008-07-29 09:13:19 +0000578/*
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000579 * Optimizer is disabled only when threaded apps are detected while
580 * the library ain't compiled for thread safety.
581 */
582static int xmlXPathDisableOptimizer = 0;
583#endif
584
Owen Taylor3473f882001-02-23 17:55:21 +0000585/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000586 * *
587 * Error handling routines *
588 * *
589 ************************************************************************/
590
Daniel Veillard24505b02005-07-28 23:49:35 +0000591/**
592 * XP_ERRORNULL:
593 * @X: the error code
594 *
595 * Macro to raise an XPath error and return NULL.
596 */
597#define XP_ERRORNULL(X) \
598 { xmlXPathErr(ctxt, X); return(NULL); }
599
William M. Brack08171912003-12-29 02:52:11 +0000600/*
601 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
602 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000603static const char *xmlXPathErrorMessages[] = {
604 "Ok\n",
605 "Number encoding\n",
606 "Unfinished literal\n",
607 "Start of literal\n",
608 "Expected $ for variable reference\n",
609 "Undefined variable\n",
610 "Invalid predicate\n",
611 "Invalid expression\n",
612 "Missing closing curly brace\n",
613 "Unregistered function\n",
614 "Invalid operand\n",
615 "Invalid type\n",
616 "Invalid number of arguments\n",
617 "Invalid context size\n",
618 "Invalid context position\n",
619 "Memory allocation error\n",
620 "Syntax error\n",
621 "Resource error\n",
622 "Sub resource error\n",
623 "Undefined namespace prefix\n",
624 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000625 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000626 "Invalid or incomplete context\n",
Jan Pokorný75801652013-12-19 15:09:14 +0100627 "Stack usage error\n",
Daniel Veillard47881282012-09-07 14:24:50 +0800628 "Forbidden variable\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000629 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000630};
William M. Brackcd65bc92005-01-06 09:39:18 +0000631#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
632 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000633/**
634 * xmlXPathErrMemory:
635 * @ctxt: an XPath context
636 * @extra: extra informations
637 *
638 * Handle a redefinition of attribute error
639 */
640static void
641xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
642{
643 if (ctxt != NULL) {
644 if (extra) {
645 xmlChar buf[200];
646
647 xmlStrPrintf(buf, 200,
David Kilzer4472c3a2016-05-13 15:13:17 +0800648 "Memory allocation failed : %s\n",
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000649 extra);
650 ctxt->lastError.message = (char *) xmlStrdup(buf);
651 } else {
652 ctxt->lastError.message = (char *)
653 xmlStrdup(BAD_CAST "Memory allocation failed\n");
654 }
655 ctxt->lastError.domain = XML_FROM_XPATH;
656 ctxt->lastError.code = XML_ERR_NO_MEMORY;
657 if (ctxt->error != NULL)
658 ctxt->error(ctxt->userData, &ctxt->lastError);
659 } else {
660 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000661 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000662 NULL, NULL, XML_FROM_XPATH,
663 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
664 extra, NULL, NULL, 0, 0,
665 "Memory allocation failed : %s\n", extra);
666 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000667 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000668 NULL, NULL, XML_FROM_XPATH,
669 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
670 NULL, NULL, NULL, 0, 0,
671 "Memory allocation failed\n");
672 }
673}
674
675/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000676 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000677 * @ctxt: an XPath parser context
678 * @extra: extra informations
679 *
680 * Handle a redefinition of attribute error
681 */
682static void
683xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
684{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000685 if (ctxt == NULL)
686 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000687 else {
688 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000689 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000690 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000691}
692
693/**
694 * xmlXPathErr:
695 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000696 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000697 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000698 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000699 */
700void
701xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
702{
William M. Brackcd65bc92005-01-06 09:39:18 +0000703 if ((error < 0) || (error > MAXERRNO))
704 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000705 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000706 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000707 NULL, NULL, XML_FROM_XPATH,
708 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
709 XML_ERR_ERROR, NULL, 0,
710 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200711 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000712 return;
713 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000714 ctxt->error = error;
715 if (ctxt->context == NULL) {
716 __xmlRaiseError(NULL, NULL, NULL,
717 NULL, NULL, XML_FROM_XPATH,
718 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
719 XML_ERR_ERROR, NULL, 0,
720 (const char *) ctxt->base, NULL, NULL,
721 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200722 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000723 return;
724 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000725
726 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000727 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000728
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000729 ctxt->context->lastError.domain = XML_FROM_XPATH;
730 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
731 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000732 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000733 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
734 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
735 ctxt->context->lastError.node = ctxt->context->debugNode;
736 if (ctxt->context->error != NULL) {
737 ctxt->context->error(ctxt->context->userData,
738 &ctxt->context->lastError);
739 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000740 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000741 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
742 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
743 XML_ERR_ERROR, NULL, 0,
744 (const char *) ctxt->base, NULL, NULL,
745 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200746 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000747 }
748
749}
750
751/**
752 * xmlXPatherror:
753 * @ctxt: the XPath Parser context
754 * @file: the file name
755 * @line: the line number
756 * @no: the error number
757 *
758 * Formats an error message.
759 */
760void
761xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
762 int line ATTRIBUTE_UNUSED, int no) {
763 xmlXPathErr(ctxt, no);
764}
765
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000766/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000767 * *
768 * Utilities *
769 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000770 ************************************************************************/
771
772/**
773 * xsltPointerList:
774 *
775 * Pointer-list for various purposes.
776 */
777typedef struct _xmlPointerList xmlPointerList;
778typedef xmlPointerList *xmlPointerListPtr;
779struct _xmlPointerList {
780 void **items;
781 int number;
782 int size;
783};
784/*
785* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
786* and here, we should make the functions public.
787*/
788static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000789xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000790 void *item,
791 int initialSize)
792{
793 if (list->items == NULL) {
794 if (initialSize <= 0)
795 initialSize = 1;
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800796 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000797 if (list->items == NULL) {
798 xmlXPathErrMemory(NULL,
799 "xmlPointerListCreate: allocating item\n");
800 return(-1);
801 }
802 list->number = 0;
803 list->size = initialSize;
804 } else if (list->size <= list->number) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800805 if (list->size > 50000000) {
806 xmlXPathErrMemory(NULL,
807 "xmlPointerListAddSize: re-allocating item\n");
808 return(-1);
809 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000810 list->size *= 2;
811 list->items = (void **) xmlRealloc(list->items,
812 list->size * sizeof(void *));
813 if (list->items == NULL) {
814 xmlXPathErrMemory(NULL,
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800815 "xmlPointerListAddSize: re-allocating item\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000816 list->size = 0;
817 return(-1);
818 }
819 }
820 list->items[list->number++] = item;
821 return(0);
822}
823
824/**
825 * xsltPointerListCreate:
826 *
827 * Creates an xsltPointerList structure.
828 *
829 * Returns a xsltPointerList structure or NULL in case of an error.
830 */
831static xmlPointerListPtr
832xmlPointerListCreate(int initialSize)
833{
834 xmlPointerListPtr ret;
835
836 ret = xmlMalloc(sizeof(xmlPointerList));
837 if (ret == NULL) {
838 xmlXPathErrMemory(NULL,
839 "xmlPointerListCreate: allocating item\n");
840 return (NULL);
841 }
842 memset(ret, 0, sizeof(xmlPointerList));
843 if (initialSize > 0) {
844 xmlPointerListAddSize(ret, NULL, initialSize);
845 ret->number = 0;
846 }
847 return (ret);
848}
849
850/**
851 * xsltPointerListFree:
852 *
853 * Frees the xsltPointerList structure. This does not free
854 * the content of the list.
855 */
856static void
857xmlPointerListFree(xmlPointerListPtr list)
858{
859 if (list == NULL)
860 return;
861 if (list->items != NULL)
862 xmlFree(list->items);
863 xmlFree(list);
864}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000865
866/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000867 * *
868 * Parser Types *
869 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000870 ************************************************************************/
871
872/*
873 * Types are private:
874 */
875
876typedef enum {
877 XPATH_OP_END=0,
878 XPATH_OP_AND,
879 XPATH_OP_OR,
880 XPATH_OP_EQUAL,
881 XPATH_OP_CMP,
882 XPATH_OP_PLUS,
883 XPATH_OP_MULT,
884 XPATH_OP_UNION,
885 XPATH_OP_ROOT,
886 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000887 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000888 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000889 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000890 XPATH_OP_VARIABLE,
891 XPATH_OP_FUNCTION,
892 XPATH_OP_ARG,
893 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000894 XPATH_OP_FILTER, /* 17 */
895 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000896#ifdef LIBXML_XPTR_ENABLED
897 ,XPATH_OP_RANGETO
898#endif
899} xmlXPathOp;
900
901typedef enum {
902 AXIS_ANCESTOR = 1,
903 AXIS_ANCESTOR_OR_SELF,
904 AXIS_ATTRIBUTE,
905 AXIS_CHILD,
906 AXIS_DESCENDANT,
907 AXIS_DESCENDANT_OR_SELF,
908 AXIS_FOLLOWING,
909 AXIS_FOLLOWING_SIBLING,
910 AXIS_NAMESPACE,
911 AXIS_PARENT,
912 AXIS_PRECEDING,
913 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000914 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000915} xmlXPathAxisVal;
916
917typedef enum {
918 NODE_TEST_NONE = 0,
919 NODE_TEST_TYPE = 1,
920 NODE_TEST_PI = 2,
921 NODE_TEST_ALL = 3,
922 NODE_TEST_NS = 4,
923 NODE_TEST_NAME = 5
924} xmlXPathTestVal;
925
926typedef enum {
927 NODE_TYPE_NODE = 0,
928 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
929 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000930 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000931} xmlXPathTypeVal;
932
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000933typedef struct _xmlXPathStepOp xmlXPathStepOp;
934typedef xmlXPathStepOp *xmlXPathStepOpPtr;
935struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000936 xmlXPathOp op; /* The identifier of the operation */
937 int ch1; /* First child */
938 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000939 int value;
940 int value2;
941 int value3;
942 void *value4;
943 void *value5;
Nick Wellnhofer229d1f92016-08-22 13:21:57 +0200944 xmlXPathFunction cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000945 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000946};
947
948struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000949 int nbStep; /* Number of steps in this expression */
950 int maxStep; /* Maximum number of steps allocated */
951 xmlXPathStepOp *steps; /* ops for computation of this expression */
952 int last; /* index of last step in expression */
953 xmlChar *expr; /* the expression being computed */
Jan Pokornýbb654fe2016-04-13 16:56:07 +0200954 xmlDictPtr dict; /* the dictionary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000955#ifdef DEBUG_EVAL_COUNTS
956 int nb;
957 xmlChar *string;
958#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000959#ifdef XPATH_STREAMING
960 xmlPatternPtr stream;
961#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000962};
963
964/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000965 * *
966 * Forward declarations *
967 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000968 ************************************************************************/
969static void
970xmlXPathFreeValueTree(xmlNodeSetPtr obj);
971static void
972xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
973static int
974xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
975 xmlXPathStepOpPtr op, xmlNodePtr *first);
976static int
977xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000978 xmlXPathStepOpPtr op,
979 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000980
981/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000982 * *
983 * Parser Type functions *
984 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000985 ************************************************************************/
986
987/**
988 * xmlXPathNewCompExpr:
989 *
990 * Create a new Xpath component
991 *
992 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
993 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000994static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000995xmlXPathNewCompExpr(void) {
996 xmlXPathCompExprPtr cur;
997
998 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
999 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001000 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001001 return(NULL);
1002 }
1003 memset(cur, 0, sizeof(xmlXPathCompExpr));
1004 cur->maxStep = 10;
1005 cur->nbStep = 0;
1006 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1007 sizeof(xmlXPathStepOp));
1008 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001009 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001010 xmlFree(cur);
1011 return(NULL);
1012 }
1013 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1014 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +00001015#ifdef DEBUG_EVAL_COUNTS
1016 cur->nb = 0;
1017#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001018 return(cur);
1019}
1020
1021/**
1022 * xmlXPathFreeCompExpr:
1023 * @comp: an XPATH comp
1024 *
1025 * Free up the memory allocated by @comp
1026 */
1027void
Daniel Veillardf06307e2001-07-03 10:35:50 +00001028xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1029{
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001030 xmlXPathStepOpPtr op;
1031 int i;
1032
1033 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00001034 return;
Daniel Veillard4773df22004-01-23 13:15:13 +00001035 if (comp->dict == NULL) {
1036 for (i = 0; i < comp->nbStep; i++) {
1037 op = &comp->steps[i];
1038 if (op->value4 != NULL) {
1039 if (op->op == XPATH_OP_VALUE)
1040 xmlXPathFreeObject(op->value4);
1041 else
1042 xmlFree(op->value4);
1043 }
1044 if (op->value5 != NULL)
1045 xmlFree(op->value5);
1046 }
1047 } else {
1048 for (i = 0; i < comp->nbStep; i++) {
1049 op = &comp->steps[i];
1050 if (op->value4 != NULL) {
1051 if (op->op == XPATH_OP_VALUE)
1052 xmlXPathFreeObject(op->value4);
1053 }
1054 }
1055 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001056 }
1057 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00001058 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001059 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001060#ifdef DEBUG_EVAL_COUNTS
1061 if (comp->string != NULL) {
1062 xmlFree(comp->string);
1063 }
1064#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +00001065#ifdef XPATH_STREAMING
1066 if (comp->stream != NULL) {
1067 xmlFreePatternList(comp->stream);
1068 }
1069#endif
Daniel Veillard118aed72002-09-24 14:13:13 +00001070 if (comp->expr != NULL) {
1071 xmlFree(comp->expr);
1072 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001073
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001074 xmlFree(comp);
1075}
1076
1077/**
1078 * xmlXPathCompExprAdd:
1079 * @comp: the compiled expression
1080 * @ch1: first child index
1081 * @ch2: second child index
1082 * @op: an op
1083 * @value: the first int value
1084 * @value2: the second int value
1085 * @value3: the third int value
1086 * @value4: the first string value
1087 * @value5: the second string value
1088 *
William M. Brack08171912003-12-29 02:52:11 +00001089 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001090 *
1091 * Returns -1 in case of failure, the index otherwise
1092 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001093static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001094xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1095 xmlXPathOp op, int value,
1096 int value2, int value3, void *value4, void *value5) {
1097 if (comp->nbStep >= comp->maxStep) {
1098 xmlXPathStepOp *real;
1099
Daniel Veillardcd852ad2012-07-30 10:12:18 +08001100 if (comp->maxStep >= XPATH_MAX_STEPS) {
1101 xmlXPathErrMemory(NULL, "adding step\n");
1102 return(-1);
1103 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001104 comp->maxStep *= 2;
1105 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1106 comp->maxStep * sizeof(xmlXPathStepOp));
1107 if (real == NULL) {
1108 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001109 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001110 return(-1);
1111 }
1112 comp->steps = real;
1113 }
1114 comp->last = comp->nbStep;
1115 comp->steps[comp->nbStep].ch1 = ch1;
1116 comp->steps[comp->nbStep].ch2 = ch2;
1117 comp->steps[comp->nbStep].op = op;
1118 comp->steps[comp->nbStep].value = value;
1119 comp->steps[comp->nbStep].value2 = value2;
1120 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +00001121 if ((comp->dict != NULL) &&
1122 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1123 (op == XPATH_OP_COLLECT))) {
1124 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001125 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001126 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001127 xmlFree(value4);
1128 } else
1129 comp->steps[comp->nbStep].value4 = NULL;
1130 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001131 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001132 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001133 xmlFree(value5);
1134 } else
1135 comp->steps[comp->nbStep].value5 = NULL;
1136 } else {
1137 comp->steps[comp->nbStep].value4 = value4;
1138 comp->steps[comp->nbStep].value5 = value5;
1139 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00001140 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001141 return(comp->nbStep++);
1142}
1143
Daniel Veillardf06307e2001-07-03 10:35:50 +00001144/**
1145 * xmlXPathCompSwap:
1146 * @comp: the compiled expression
1147 * @op: operation index
1148 *
1149 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +00001150 */
1151static void
1152xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1153 int tmp;
1154
Daniel Veillardbc6f7592002-04-16 07:49:59 +00001155#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +00001156 /*
1157 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +00001158 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +00001159 * application
1160 */
1161 if (xmlXPathDisableOptimizer)
1162 return;
1163#endif
1164
Daniel Veillardf06307e2001-07-03 10:35:50 +00001165 tmp = op->ch1;
1166 op->ch1 = op->ch2;
1167 op->ch2 = tmp;
1168}
1169
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001170#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1171 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1172 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001173#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1174 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1175 (op), (val), (val2), (val3), (val4), (val5))
1176
Daniel Veillard45490ae2008-07-29 09:13:19 +00001177#define PUSH_LEAVE_EXPR(op, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001178xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1179
Daniel Veillard45490ae2008-07-29 09:13:19 +00001180#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001181xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1182
Daniel Veillard45490ae2008-07-29 09:13:19 +00001183#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +00001184xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1185 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001186
1187/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +00001188 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001189 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001190 * *
1191 ************************************************************************/
1192
1193/* #define XP_DEFAULT_CACHE_ON */
1194
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001195#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001196
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001197typedef struct _xmlXPathContextCache xmlXPathContextCache;
1198typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1199struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00001200 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1201 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1202 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1203 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1204 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001205 int maxNodeset;
1206 int maxString;
1207 int maxBoolean;
1208 int maxNumber;
1209 int maxMisc;
1210#ifdef XP_DEBUG_OBJ_USAGE
1211 int dbgCachedAll;
1212 int dbgCachedNodeset;
1213 int dbgCachedString;
1214 int dbgCachedBool;
1215 int dbgCachedNumber;
1216 int dbgCachedPoint;
1217 int dbgCachedRange;
1218 int dbgCachedLocset;
1219 int dbgCachedUsers;
1220 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001221 int dbgCachedUndefined;
1222
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001223
1224 int dbgReusedAll;
1225 int dbgReusedNodeset;
1226 int dbgReusedString;
1227 int dbgReusedBool;
1228 int dbgReusedNumber;
1229 int dbgReusedPoint;
1230 int dbgReusedRange;
1231 int dbgReusedLocset;
1232 int dbgReusedUsers;
1233 int dbgReusedXSLTTree;
1234 int dbgReusedUndefined;
1235
1236#endif
1237};
1238
1239/************************************************************************
1240 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001241 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +00001242 * *
1243 ************************************************************************/
1244
Daniel Veillard45490ae2008-07-29 09:13:19 +00001245#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +00001246 xmlGenericError(xmlGenericErrorContext, \
1247 "Internal error at %s:%d\n", \
1248 __FILE__, __LINE__);
1249
1250#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001251static void
1252xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001253 int i;
1254 char shift[100];
1255
1256 for (i = 0;((i < depth) && (i < 25));i++)
1257 shift[2 * i] = shift[2 * i + 1] = ' ';
1258 shift[2 * i] = shift[2 * i + 1] = 0;
1259 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001260 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001261 fprintf(output, "Node is NULL !\n");
1262 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001263
Owen Taylor3473f882001-02-23 17:55:21 +00001264 }
1265
1266 if ((cur->type == XML_DOCUMENT_NODE) ||
1267 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001268 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001269 fprintf(output, " /\n");
1270 } else if (cur->type == XML_ATTRIBUTE_NODE)
1271 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1272 else
1273 xmlDebugDumpOneNode(output, cur, depth);
1274}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001275static void
1276xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001277 xmlNodePtr tmp;
1278 int i;
1279 char shift[100];
1280
1281 for (i = 0;((i < depth) && (i < 25));i++)
1282 shift[2 * i] = shift[2 * i + 1] = ' ';
1283 shift[2 * i] = shift[2 * i + 1] = 0;
1284 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001285 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001286 fprintf(output, "Node is NULL !\n");
1287 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001288
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001289 }
1290
1291 while (cur != NULL) {
1292 tmp = cur;
1293 cur = cur->next;
1294 xmlDebugDumpOneNode(output, tmp, depth);
1295 }
1296}
Owen Taylor3473f882001-02-23 17:55:21 +00001297
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001298static void
1299xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001300 int i;
1301 char shift[100];
1302
1303 for (i = 0;((i < depth) && (i < 25));i++)
1304 shift[2 * i] = shift[2 * i + 1] = ' ';
1305 shift[2 * i] = shift[2 * i + 1] = 0;
1306
1307 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001308 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001309 fprintf(output, "NodeSet is NULL !\n");
1310 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001311
Owen Taylor3473f882001-02-23 17:55:21 +00001312 }
1313
Daniel Veillard911f49a2001-04-07 15:39:35 +00001314 if (cur != NULL) {
1315 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1316 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001317 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +00001318 fprintf(output, "%d", i + 1);
1319 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1320 }
Owen Taylor3473f882001-02-23 17:55:21 +00001321 }
1322}
1323
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001324static void
1325xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001326 int i;
1327 char shift[100];
1328
1329 for (i = 0;((i < depth) && (i < 25));i++)
1330 shift[2 * i] = shift[2 * i + 1] = ' ';
1331 shift[2 * i] = shift[2 * i + 1] = 0;
1332
1333 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001334 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001335 fprintf(output, "Value Tree is NULL !\n");
1336 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001337
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001338 }
1339
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001340 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001341 fprintf(output, "%d", i + 1);
1342 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1343}
Owen Taylor3473f882001-02-23 17:55:21 +00001344#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001345static void
1346xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001347 int i;
1348 char shift[100];
1349
1350 for (i = 0;((i < depth) && (i < 25));i++)
1351 shift[2 * i] = shift[2 * i + 1] = ' ';
1352 shift[2 * i] = shift[2 * i + 1] = 0;
1353
1354 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001355 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001356 fprintf(output, "LocationSet is NULL !\n");
1357 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001358
Owen Taylor3473f882001-02-23 17:55:21 +00001359 }
1360
1361 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001362 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001363 fprintf(output, "%d : ", i + 1);
1364 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1365 }
1366}
Daniel Veillard017b1082001-06-21 11:20:21 +00001367#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001368
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00001369/**
1370 * xmlXPathDebugDumpObject:
1371 * @output: the FILE * to dump the output
1372 * @cur: the object to inspect
1373 * @depth: indentation level
1374 *
1375 * Dump the content of the object for debugging purposes
1376 */
1377void
1378xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001379 int i;
1380 char shift[100];
1381
Daniel Veillarda82b1822004-11-08 16:24:57 +00001382 if (output == NULL) return;
1383
Owen Taylor3473f882001-02-23 17:55:21 +00001384 for (i = 0;((i < depth) && (i < 25));i++)
1385 shift[2 * i] = shift[2 * i + 1] = ' ';
1386 shift[2 * i] = shift[2 * i + 1] = 0;
1387
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001388
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001389 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001390
1391 if (cur == NULL) {
1392 fprintf(output, "Object is empty (NULL)\n");
1393 return;
1394 }
1395 switch(cur->type) {
1396 case XPATH_UNDEFINED:
1397 fprintf(output, "Object is uninitialized\n");
1398 break;
1399 case XPATH_NODESET:
1400 fprintf(output, "Object is a Node Set :\n");
1401 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1402 break;
1403 case XPATH_XSLT_TREE:
1404 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001405 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001406 break;
1407 case XPATH_BOOLEAN:
1408 fprintf(output, "Object is a Boolean : ");
1409 if (cur->boolval) fprintf(output, "true\n");
1410 else fprintf(output, "false\n");
1411 break;
1412 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001413 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001414 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001415 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001416 break;
1417 case -1:
1418 fprintf(output, "Object is a number : -Infinity\n");
1419 break;
1420 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001421 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001422 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001423 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1424 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001425 } else {
1426 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1427 }
1428 }
Owen Taylor3473f882001-02-23 17:55:21 +00001429 break;
1430 case XPATH_STRING:
1431 fprintf(output, "Object is a string : ");
1432 xmlDebugDumpString(output, cur->stringval);
1433 fprintf(output, "\n");
1434 break;
1435 case XPATH_POINT:
1436 fprintf(output, "Object is a point : index %d in node", cur->index);
1437 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1438 fprintf(output, "\n");
1439 break;
1440 case XPATH_RANGE:
1441 if ((cur->user2 == NULL) ||
1442 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1443 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001444 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001445 if (cur->index >= 0)
1446 fprintf(output, "index %d in ", cur->index);
1447 fprintf(output, "node\n");
1448 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1449 depth + 1);
1450 } else {
1451 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001452 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001453 fprintf(output, "From ");
1454 if (cur->index >= 0)
1455 fprintf(output, "index %d in ", cur->index);
1456 fprintf(output, "node\n");
1457 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1458 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001459 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001460 fprintf(output, "To ");
1461 if (cur->index2 >= 0)
1462 fprintf(output, "index %d in ", cur->index2);
1463 fprintf(output, "node\n");
1464 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1465 depth + 1);
1466 fprintf(output, "\n");
1467 }
1468 break;
1469 case XPATH_LOCATIONSET:
1470#if defined(LIBXML_XPTR_ENABLED)
1471 fprintf(output, "Object is a Location Set:\n");
1472 xmlXPathDebugDumpLocationSet(output,
1473 (xmlLocationSetPtr) cur->user, depth);
1474#endif
1475 break;
1476 case XPATH_USERS:
1477 fprintf(output, "Object is user defined\n");
1478 break;
1479 }
1480}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001481
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001482static void
1483xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001484 xmlXPathStepOpPtr op, int depth) {
1485 int i;
1486 char shift[100];
1487
1488 for (i = 0;((i < depth) && (i < 25));i++)
1489 shift[2 * i] = shift[2 * i + 1] = ' ';
1490 shift[2 * i] = shift[2 * i + 1] = 0;
1491
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001492 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001493 if (op == NULL) {
1494 fprintf(output, "Step is NULL\n");
1495 return;
1496 }
1497 switch (op->op) {
1498 case XPATH_OP_END:
1499 fprintf(output, "END"); break;
1500 case XPATH_OP_AND:
1501 fprintf(output, "AND"); break;
1502 case XPATH_OP_OR:
1503 fprintf(output, "OR"); break;
1504 case XPATH_OP_EQUAL:
1505 if (op->value)
1506 fprintf(output, "EQUAL =");
1507 else
1508 fprintf(output, "EQUAL !=");
1509 break;
1510 case XPATH_OP_CMP:
1511 if (op->value)
1512 fprintf(output, "CMP <");
1513 else
1514 fprintf(output, "CMP >");
1515 if (!op->value2)
1516 fprintf(output, "=");
1517 break;
1518 case XPATH_OP_PLUS:
1519 if (op->value == 0)
1520 fprintf(output, "PLUS -");
1521 else if (op->value == 1)
1522 fprintf(output, "PLUS +");
1523 else if (op->value == 2)
1524 fprintf(output, "PLUS unary -");
1525 else if (op->value == 3)
1526 fprintf(output, "PLUS unary - -");
1527 break;
1528 case XPATH_OP_MULT:
1529 if (op->value == 0)
1530 fprintf(output, "MULT *");
1531 else if (op->value == 1)
1532 fprintf(output, "MULT div");
1533 else
1534 fprintf(output, "MULT mod");
1535 break;
1536 case XPATH_OP_UNION:
1537 fprintf(output, "UNION"); break;
1538 case XPATH_OP_ROOT:
1539 fprintf(output, "ROOT"); break;
1540 case XPATH_OP_NODE:
1541 fprintf(output, "NODE"); break;
1542 case XPATH_OP_RESET:
1543 fprintf(output, "RESET"); break;
1544 case XPATH_OP_SORT:
1545 fprintf(output, "SORT"); break;
1546 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001547 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1548 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1549 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001550 const xmlChar *prefix = op->value4;
1551 const xmlChar *name = op->value5;
1552
1553 fprintf(output, "COLLECT ");
1554 switch (axis) {
1555 case AXIS_ANCESTOR:
1556 fprintf(output, " 'ancestors' "); break;
1557 case AXIS_ANCESTOR_OR_SELF:
1558 fprintf(output, " 'ancestors-or-self' "); break;
1559 case AXIS_ATTRIBUTE:
1560 fprintf(output, " 'attributes' "); break;
1561 case AXIS_CHILD:
1562 fprintf(output, " 'child' "); break;
1563 case AXIS_DESCENDANT:
1564 fprintf(output, " 'descendant' "); break;
1565 case AXIS_DESCENDANT_OR_SELF:
1566 fprintf(output, " 'descendant-or-self' "); break;
1567 case AXIS_FOLLOWING:
1568 fprintf(output, " 'following' "); break;
1569 case AXIS_FOLLOWING_SIBLING:
1570 fprintf(output, " 'following-siblings' "); break;
1571 case AXIS_NAMESPACE:
1572 fprintf(output, " 'namespace' "); break;
1573 case AXIS_PARENT:
1574 fprintf(output, " 'parent' "); break;
1575 case AXIS_PRECEDING:
1576 fprintf(output, " 'preceding' "); break;
1577 case AXIS_PRECEDING_SIBLING:
1578 fprintf(output, " 'preceding-sibling' "); break;
1579 case AXIS_SELF:
1580 fprintf(output, " 'self' "); break;
1581 }
1582 switch (test) {
1583 case NODE_TEST_NONE:
1584 fprintf(output, "'none' "); break;
1585 case NODE_TEST_TYPE:
1586 fprintf(output, "'type' "); break;
1587 case NODE_TEST_PI:
1588 fprintf(output, "'PI' "); break;
1589 case NODE_TEST_ALL:
1590 fprintf(output, "'all' "); break;
1591 case NODE_TEST_NS:
1592 fprintf(output, "'namespace' "); break;
1593 case NODE_TEST_NAME:
1594 fprintf(output, "'name' "); break;
1595 }
1596 switch (type) {
1597 case NODE_TYPE_NODE:
1598 fprintf(output, "'node' "); break;
1599 case NODE_TYPE_COMMENT:
1600 fprintf(output, "'comment' "); break;
1601 case NODE_TYPE_TEXT:
1602 fprintf(output, "'text' "); break;
1603 case NODE_TYPE_PI:
1604 fprintf(output, "'PI' "); break;
1605 }
1606 if (prefix != NULL)
1607 fprintf(output, "%s:", prefix);
1608 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001609 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001610 break;
1611
1612 }
1613 case XPATH_OP_VALUE: {
1614 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1615
1616 fprintf(output, "ELEM ");
1617 xmlXPathDebugDumpObject(output, object, 0);
1618 goto finish;
1619 }
1620 case XPATH_OP_VARIABLE: {
1621 const xmlChar *prefix = op->value5;
1622 const xmlChar *name = op->value4;
1623
1624 if (prefix != NULL)
1625 fprintf(output, "VARIABLE %s:%s", prefix, name);
1626 else
1627 fprintf(output, "VARIABLE %s", name);
1628 break;
1629 }
1630 case XPATH_OP_FUNCTION: {
1631 int nbargs = op->value;
1632 const xmlChar *prefix = op->value5;
1633 const xmlChar *name = op->value4;
1634
1635 if (prefix != NULL)
1636 fprintf(output, "FUNCTION %s:%s(%d args)",
1637 prefix, name, nbargs);
1638 else
1639 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1640 break;
1641 }
1642 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1643 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001644 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001645#ifdef LIBXML_XPTR_ENABLED
1646 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1647#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001648 default:
1649 fprintf(output, "UNKNOWN %d\n", op->op); return;
1650 }
1651 fprintf(output, "\n");
1652finish:
1653 if (op->ch1 >= 0)
1654 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1655 if (op->ch2 >= 0)
1656 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1657}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001658
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001659/**
1660 * xmlXPathDebugDumpCompExpr:
1661 * @output: the FILE * for the output
1662 * @comp: the precompiled XPath expression
1663 * @depth: the indentation level.
1664 *
1665 * Dumps the tree of the compiled XPath expression.
1666 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001667void
1668xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1669 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001670 int i;
1671 char shift[100];
1672
Daniel Veillarda82b1822004-11-08 16:24:57 +00001673 if ((output == NULL) || (comp == NULL)) return;
1674
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001675 for (i = 0;((i < depth) && (i < 25));i++)
1676 shift[2 * i] = shift[2 * i + 1] = ' ';
1677 shift[2 * i] = shift[2 * i + 1] = 0;
1678
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001679 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001680
Nick Wellnhoferca8635b2017-09-07 15:46:12 +02001681#ifdef XPATH_STREAMING
1682 if (comp->stream) {
1683 fprintf(output, "Streaming Expression\n");
1684 } else
1685#endif
1686 {
1687 fprintf(output, "Compiled Expression : %d elements\n",
1688 comp->nbStep);
1689 i = comp->last;
1690 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1691 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001692}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001693
1694#ifdef XP_DEBUG_OBJ_USAGE
1695
1696/*
1697* XPath object usage related debugging variables.
1698*/
1699static int xmlXPathDebugObjCounterUndefined = 0;
1700static int xmlXPathDebugObjCounterNodeset = 0;
1701static int xmlXPathDebugObjCounterBool = 0;
1702static int xmlXPathDebugObjCounterNumber = 0;
1703static int xmlXPathDebugObjCounterString = 0;
1704static int xmlXPathDebugObjCounterPoint = 0;
1705static int xmlXPathDebugObjCounterRange = 0;
1706static int xmlXPathDebugObjCounterLocset = 0;
1707static int xmlXPathDebugObjCounterUsers = 0;
1708static int xmlXPathDebugObjCounterXSLTTree = 0;
1709static int xmlXPathDebugObjCounterAll = 0;
1710
1711static int xmlXPathDebugObjTotalUndefined = 0;
1712static int xmlXPathDebugObjTotalNodeset = 0;
1713static int xmlXPathDebugObjTotalBool = 0;
1714static int xmlXPathDebugObjTotalNumber = 0;
1715static int xmlXPathDebugObjTotalString = 0;
1716static int xmlXPathDebugObjTotalPoint = 0;
1717static int xmlXPathDebugObjTotalRange = 0;
1718static int xmlXPathDebugObjTotalLocset = 0;
1719static int xmlXPathDebugObjTotalUsers = 0;
1720static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001721static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001722
1723static int xmlXPathDebugObjMaxUndefined = 0;
1724static int xmlXPathDebugObjMaxNodeset = 0;
1725static int xmlXPathDebugObjMaxBool = 0;
1726static int xmlXPathDebugObjMaxNumber = 0;
1727static int xmlXPathDebugObjMaxString = 0;
1728static int xmlXPathDebugObjMaxPoint = 0;
1729static int xmlXPathDebugObjMaxRange = 0;
1730static int xmlXPathDebugObjMaxLocset = 0;
1731static int xmlXPathDebugObjMaxUsers = 0;
1732static int xmlXPathDebugObjMaxXSLTTree = 0;
1733static int xmlXPathDebugObjMaxAll = 0;
1734
1735/* REVISIT TODO: Make this static when committing */
1736static void
1737xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1738{
1739 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001740 if (ctxt->cache != NULL) {
1741 xmlXPathContextCachePtr cache =
1742 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001743
1744 cache->dbgCachedAll = 0;
1745 cache->dbgCachedNodeset = 0;
1746 cache->dbgCachedString = 0;
1747 cache->dbgCachedBool = 0;
1748 cache->dbgCachedNumber = 0;
1749 cache->dbgCachedPoint = 0;
1750 cache->dbgCachedRange = 0;
1751 cache->dbgCachedLocset = 0;
1752 cache->dbgCachedUsers = 0;
1753 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001754 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001755
1756 cache->dbgReusedAll = 0;
1757 cache->dbgReusedNodeset = 0;
1758 cache->dbgReusedString = 0;
1759 cache->dbgReusedBool = 0;
1760 cache->dbgReusedNumber = 0;
1761 cache->dbgReusedPoint = 0;
1762 cache->dbgReusedRange = 0;
1763 cache->dbgReusedLocset = 0;
1764 cache->dbgReusedUsers = 0;
1765 cache->dbgReusedXSLTTree = 0;
1766 cache->dbgReusedUndefined = 0;
1767 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001768 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001769
1770 xmlXPathDebugObjCounterUndefined = 0;
1771 xmlXPathDebugObjCounterNodeset = 0;
1772 xmlXPathDebugObjCounterBool = 0;
1773 xmlXPathDebugObjCounterNumber = 0;
1774 xmlXPathDebugObjCounterString = 0;
1775 xmlXPathDebugObjCounterPoint = 0;
1776 xmlXPathDebugObjCounterRange = 0;
1777 xmlXPathDebugObjCounterLocset = 0;
1778 xmlXPathDebugObjCounterUsers = 0;
1779 xmlXPathDebugObjCounterXSLTTree = 0;
1780 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001781
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001782 xmlXPathDebugObjTotalUndefined = 0;
1783 xmlXPathDebugObjTotalNodeset = 0;
1784 xmlXPathDebugObjTotalBool = 0;
1785 xmlXPathDebugObjTotalNumber = 0;
1786 xmlXPathDebugObjTotalString = 0;
1787 xmlXPathDebugObjTotalPoint = 0;
1788 xmlXPathDebugObjTotalRange = 0;
1789 xmlXPathDebugObjTotalLocset = 0;
1790 xmlXPathDebugObjTotalUsers = 0;
1791 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001792 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001793
1794 xmlXPathDebugObjMaxUndefined = 0;
1795 xmlXPathDebugObjMaxNodeset = 0;
1796 xmlXPathDebugObjMaxBool = 0;
1797 xmlXPathDebugObjMaxNumber = 0;
1798 xmlXPathDebugObjMaxString = 0;
1799 xmlXPathDebugObjMaxPoint = 0;
1800 xmlXPathDebugObjMaxRange = 0;
1801 xmlXPathDebugObjMaxLocset = 0;
1802 xmlXPathDebugObjMaxUsers = 0;
1803 xmlXPathDebugObjMaxXSLTTree = 0;
1804 xmlXPathDebugObjMaxAll = 0;
1805
1806}
1807
1808static void
1809xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1810 xmlXPathObjectType objType)
1811{
1812 int isCached = 0;
1813
1814 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001815 if (ctxt->cache != NULL) {
1816 xmlXPathContextCachePtr cache =
1817 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001818
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001819 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001820
1821 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001822 switch (objType) {
1823 case XPATH_UNDEFINED:
1824 cache->dbgReusedUndefined++;
1825 break;
1826 case XPATH_NODESET:
1827 cache->dbgReusedNodeset++;
1828 break;
1829 case XPATH_BOOLEAN:
1830 cache->dbgReusedBool++;
1831 break;
1832 case XPATH_NUMBER:
1833 cache->dbgReusedNumber++;
1834 break;
1835 case XPATH_STRING:
1836 cache->dbgReusedString++;
1837 break;
1838 case XPATH_POINT:
1839 cache->dbgReusedPoint++;
1840 break;
1841 case XPATH_RANGE:
1842 cache->dbgReusedRange++;
1843 break;
1844 case XPATH_LOCATIONSET:
1845 cache->dbgReusedLocset++;
1846 break;
1847 case XPATH_USERS:
1848 cache->dbgReusedUsers++;
1849 break;
1850 case XPATH_XSLT_TREE:
1851 cache->dbgReusedXSLTTree++;
1852 break;
1853 default:
1854 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001855 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001856 }
1857 }
1858
1859 switch (objType) {
1860 case XPATH_UNDEFINED:
1861 if (! isCached)
1862 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001863 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001864 if (xmlXPathDebugObjCounterUndefined >
1865 xmlXPathDebugObjMaxUndefined)
1866 xmlXPathDebugObjMaxUndefined =
1867 xmlXPathDebugObjCounterUndefined;
1868 break;
1869 case XPATH_NODESET:
1870 if (! isCached)
1871 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001872 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001873 if (xmlXPathDebugObjCounterNodeset >
1874 xmlXPathDebugObjMaxNodeset)
1875 xmlXPathDebugObjMaxNodeset =
1876 xmlXPathDebugObjCounterNodeset;
1877 break;
1878 case XPATH_BOOLEAN:
1879 if (! isCached)
1880 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001881 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001882 if (xmlXPathDebugObjCounterBool >
1883 xmlXPathDebugObjMaxBool)
1884 xmlXPathDebugObjMaxBool =
1885 xmlXPathDebugObjCounterBool;
1886 break;
1887 case XPATH_NUMBER:
1888 if (! isCached)
1889 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001890 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001891 if (xmlXPathDebugObjCounterNumber >
1892 xmlXPathDebugObjMaxNumber)
1893 xmlXPathDebugObjMaxNumber =
1894 xmlXPathDebugObjCounterNumber;
1895 break;
1896 case XPATH_STRING:
1897 if (! isCached)
1898 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001899 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001900 if (xmlXPathDebugObjCounterString >
1901 xmlXPathDebugObjMaxString)
1902 xmlXPathDebugObjMaxString =
1903 xmlXPathDebugObjCounterString;
1904 break;
1905 case XPATH_POINT:
1906 if (! isCached)
1907 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001908 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001909 if (xmlXPathDebugObjCounterPoint >
1910 xmlXPathDebugObjMaxPoint)
1911 xmlXPathDebugObjMaxPoint =
1912 xmlXPathDebugObjCounterPoint;
1913 break;
1914 case XPATH_RANGE:
1915 if (! isCached)
1916 xmlXPathDebugObjTotalRange++;
1917 xmlXPathDebugObjCounterRange++;
1918 if (xmlXPathDebugObjCounterRange >
1919 xmlXPathDebugObjMaxRange)
1920 xmlXPathDebugObjMaxRange =
1921 xmlXPathDebugObjCounterRange;
1922 break;
1923 case XPATH_LOCATIONSET:
1924 if (! isCached)
1925 xmlXPathDebugObjTotalLocset++;
1926 xmlXPathDebugObjCounterLocset++;
1927 if (xmlXPathDebugObjCounterLocset >
1928 xmlXPathDebugObjMaxLocset)
1929 xmlXPathDebugObjMaxLocset =
1930 xmlXPathDebugObjCounterLocset;
1931 break;
1932 case XPATH_USERS:
1933 if (! isCached)
1934 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001935 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001936 if (xmlXPathDebugObjCounterUsers >
1937 xmlXPathDebugObjMaxUsers)
1938 xmlXPathDebugObjMaxUsers =
1939 xmlXPathDebugObjCounterUsers;
1940 break;
1941 case XPATH_XSLT_TREE:
1942 if (! isCached)
1943 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001944 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001945 if (xmlXPathDebugObjCounterXSLTTree >
1946 xmlXPathDebugObjMaxXSLTTree)
1947 xmlXPathDebugObjMaxXSLTTree =
1948 xmlXPathDebugObjCounterXSLTTree;
1949 break;
1950 default:
1951 break;
1952 }
1953 if (! isCached)
1954 xmlXPathDebugObjTotalAll++;
1955 xmlXPathDebugObjCounterAll++;
1956 if (xmlXPathDebugObjCounterAll >
1957 xmlXPathDebugObjMaxAll)
1958 xmlXPathDebugObjMaxAll =
1959 xmlXPathDebugObjCounterAll;
1960}
1961
1962static void
1963xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1964 xmlXPathObjectType objType)
1965{
1966 int isCached = 0;
1967
1968 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001969 if (ctxt->cache != NULL) {
1970 xmlXPathContextCachePtr cache =
1971 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001972
Daniel Veillard45490ae2008-07-29 09:13:19 +00001973 isCached = 1;
1974
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001975 cache->dbgCachedAll++;
1976 switch (objType) {
1977 case XPATH_UNDEFINED:
1978 cache->dbgCachedUndefined++;
1979 break;
1980 case XPATH_NODESET:
1981 cache->dbgCachedNodeset++;
1982 break;
1983 case XPATH_BOOLEAN:
1984 cache->dbgCachedBool++;
1985 break;
1986 case XPATH_NUMBER:
1987 cache->dbgCachedNumber++;
1988 break;
1989 case XPATH_STRING:
1990 cache->dbgCachedString++;
1991 break;
1992 case XPATH_POINT:
1993 cache->dbgCachedPoint++;
1994 break;
1995 case XPATH_RANGE:
1996 cache->dbgCachedRange++;
1997 break;
1998 case XPATH_LOCATIONSET:
1999 cache->dbgCachedLocset++;
2000 break;
2001 case XPATH_USERS:
2002 cache->dbgCachedUsers++;
2003 break;
2004 case XPATH_XSLT_TREE:
2005 cache->dbgCachedXSLTTree++;
2006 break;
2007 default:
2008 break;
2009 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002010
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002011 }
2012 }
2013 switch (objType) {
2014 case XPATH_UNDEFINED:
2015 xmlXPathDebugObjCounterUndefined--;
2016 break;
2017 case XPATH_NODESET:
2018 xmlXPathDebugObjCounterNodeset--;
2019 break;
2020 case XPATH_BOOLEAN:
2021 xmlXPathDebugObjCounterBool--;
2022 break;
2023 case XPATH_NUMBER:
2024 xmlXPathDebugObjCounterNumber--;
2025 break;
2026 case XPATH_STRING:
2027 xmlXPathDebugObjCounterString--;
2028 break;
2029 case XPATH_POINT:
2030 xmlXPathDebugObjCounterPoint--;
2031 break;
2032 case XPATH_RANGE:
2033 xmlXPathDebugObjCounterRange--;
2034 break;
2035 case XPATH_LOCATIONSET:
2036 xmlXPathDebugObjCounterLocset--;
2037 break;
2038 case XPATH_USERS:
2039 xmlXPathDebugObjCounterUsers--;
2040 break;
2041 case XPATH_XSLT_TREE:
2042 xmlXPathDebugObjCounterXSLTTree--;
2043 break;
2044 default:
2045 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002046 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002047 xmlXPathDebugObjCounterAll--;
2048}
2049
2050/* REVISIT TODO: Make this static when committing */
2051static void
2052xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2053{
2054 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2055 reqXSLTTree, reqUndefined;
2056 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2057 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2058 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2059 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2060 int leftObjs = xmlXPathDebugObjCounterAll;
2061
2062 reqAll = xmlXPathDebugObjTotalAll;
2063 reqNodeset = xmlXPathDebugObjTotalNodeset;
2064 reqString = xmlXPathDebugObjTotalString;
2065 reqBool = xmlXPathDebugObjTotalBool;
2066 reqNumber = xmlXPathDebugObjTotalNumber;
2067 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2068 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002069
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002070 printf("# XPath object usage:\n");
2071
2072 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002073 if (ctxt->cache != NULL) {
2074 xmlXPathContextCachePtr cache =
2075 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002076
2077 reAll = cache->dbgReusedAll;
2078 reqAll += reAll;
2079 reNodeset = cache->dbgReusedNodeset;
2080 reqNodeset += reNodeset;
2081 reString = cache->dbgReusedString;
2082 reqString += reString;
2083 reBool = cache->dbgReusedBool;
2084 reqBool += reBool;
2085 reNumber = cache->dbgReusedNumber;
2086 reqNumber += reNumber;
2087 reXSLTTree = cache->dbgReusedXSLTTree;
2088 reqXSLTTree += reXSLTTree;
2089 reUndefined = cache->dbgReusedUndefined;
2090 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002091
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002092 caAll = cache->dbgCachedAll;
2093 caBool = cache->dbgCachedBool;
2094 caNodeset = cache->dbgCachedNodeset;
2095 caString = cache->dbgCachedString;
2096 caNumber = cache->dbgCachedNumber;
2097 caXSLTTree = cache->dbgCachedXSLTTree;
2098 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002099
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002100 if (cache->nodesetObjs)
2101 leftObjs -= cache->nodesetObjs->number;
2102 if (cache->stringObjs)
2103 leftObjs -= cache->stringObjs->number;
2104 if (cache->booleanObjs)
2105 leftObjs -= cache->booleanObjs->number;
2106 if (cache->numberObjs)
2107 leftObjs -= cache->numberObjs->number;
2108 if (cache->miscObjs)
2109 leftObjs -= cache->miscObjs->number;
2110 }
2111 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002112
2113 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002114 printf("# total : %d\n", reqAll);
2115 printf("# left : %d\n", leftObjs);
2116 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2117 printf("# reused : %d\n", reAll);
2118 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2119
2120 printf("# node-sets\n");
2121 printf("# total : %d\n", reqNodeset);
2122 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2123 printf("# reused : %d\n", reNodeset);
2124 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2125
2126 printf("# strings\n");
2127 printf("# total : %d\n", reqString);
2128 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2129 printf("# reused : %d\n", reString);
2130 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2131
2132 printf("# booleans\n");
2133 printf("# total : %d\n", reqBool);
2134 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2135 printf("# reused : %d\n", reBool);
2136 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2137
2138 printf("# numbers\n");
2139 printf("# total : %d\n", reqNumber);
2140 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2141 printf("# reused : %d\n", reNumber);
2142 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2143
2144 printf("# XSLT result tree fragments\n");
2145 printf("# total : %d\n", reqXSLTTree);
2146 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2147 printf("# reused : %d\n", reXSLTTree);
2148 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2149
2150 printf("# undefined\n");
2151 printf("# total : %d\n", reqUndefined);
2152 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2153 printf("# reused : %d\n", reUndefined);
2154 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2155
2156}
2157
2158#endif /* XP_DEBUG_OBJ_USAGE */
2159
Daniel Veillard017b1082001-06-21 11:20:21 +00002160#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002161
2162/************************************************************************
2163 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002164 * XPath object caching *
2165 * *
2166 ************************************************************************/
2167
2168/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002169 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002170 *
2171 * Create a new object cache
2172 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002173 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002174 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002175static xmlXPathContextCachePtr
2176xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002177{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002178 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002179
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002180 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002181 if (ret == NULL) {
2182 xmlXPathErrMemory(NULL, "creating object cache\n");
2183 return(NULL);
2184 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002185 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002186 ret->maxNodeset = 100;
2187 ret->maxString = 100;
2188 ret->maxBoolean = 100;
2189 ret->maxNumber = 100;
2190 ret->maxMisc = 100;
2191 return(ret);
2192}
2193
2194static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002195xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002196{
2197 int i;
2198 xmlXPathObjectPtr obj;
2199
2200 if (list == NULL)
2201 return;
2202
2203 for (i = 0; i < list->number; i++) {
2204 obj = list->items[i];
2205 /*
2206 * Note that it is already assured that we don't need to
2207 * look out for namespace nodes in the node-set.
2208 */
2209 if (obj->nodesetval != NULL) {
2210 if (obj->nodesetval->nodeTab != NULL)
2211 xmlFree(obj->nodesetval->nodeTab);
2212 xmlFree(obj->nodesetval);
2213 }
2214 xmlFree(obj);
2215#ifdef XP_DEBUG_OBJ_USAGE
2216 xmlXPathDebugObjCounterAll--;
2217#endif
2218 }
2219 xmlPointerListFree(list);
2220}
2221
2222static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002223xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002224{
2225 if (cache == NULL)
2226 return;
2227 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002228 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002229 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002230 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002231 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002232 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002233 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002234 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002235 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002236 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002237 xmlFree(cache);
2238}
2239
2240/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002241 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002242 *
2243 * @ctxt: the XPath context
2244 * @active: enables/disables (creates/frees) the cache
Daniel Veillard45490ae2008-07-29 09:13:19 +00002245 * @value: a value with semantics dependant on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002246 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002247 *
2248 * Creates/frees an object cache on the XPath context.
2249 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002250 * to be reused.
2251 * @options:
2252 * 0: This will set the XPath object caching:
2253 * @value:
2254 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002255 * to be cached per slot
2256 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002257 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002258 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002259 *
2260 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2261 */
2262int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002263xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2264 int active,
2265 int value,
2266 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002267{
2268 if (ctxt == NULL)
2269 return(-1);
2270 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002271 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002272
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002273 if (ctxt->cache == NULL) {
2274 ctxt->cache = xmlXPathNewCache();
2275 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002276 return(-1);
2277 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002278 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002279 if (options == 0) {
2280 if (value < 0)
2281 value = 100;
2282 cache->maxNodeset = value;
2283 cache->maxString = value;
2284 cache->maxNumber = value;
2285 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002286 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002287 }
2288 } else if (ctxt->cache != NULL) {
2289 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2290 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002291 }
2292 return(0);
2293}
2294
2295/**
2296 * xmlXPathCacheWrapNodeSet:
2297 * @ctxt: the XPath context
2298 * @val: the NodePtr value
2299 *
2300 * This is the cached version of xmlXPathWrapNodeSet().
2301 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2302 *
2303 * Returns the created or reused object.
2304 */
2305static xmlXPathObjectPtr
2306xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002307{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002308 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2309 xmlXPathContextCachePtr cache =
2310 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002311
2312 if ((cache->miscObjs != NULL) &&
2313 (cache->miscObjs->number != 0))
2314 {
2315 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002316
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002317 ret = (xmlXPathObjectPtr)
2318 cache->miscObjs->items[--cache->miscObjs->number];
2319 ret->type = XPATH_NODESET;
2320 ret->nodesetval = val;
2321#ifdef XP_DEBUG_OBJ_USAGE
2322 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2323#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00002324 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002325 }
2326 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002327
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002328 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00002329
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002330}
2331
2332/**
2333 * xmlXPathCacheWrapString:
2334 * @ctxt: the XPath context
2335 * @val: the xmlChar * value
2336 *
2337 * This is the cached version of xmlXPathWrapString().
2338 * Wraps the @val string into an XPath object.
2339 *
2340 * Returns the created or reused object.
2341 */
2342static xmlXPathObjectPtr
2343xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002344{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002345 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2346 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002347
2348 if ((cache->stringObjs != NULL) &&
2349 (cache->stringObjs->number != 0))
2350 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002351
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002352 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002353
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002354 ret = (xmlXPathObjectPtr)
2355 cache->stringObjs->items[--cache->stringObjs->number];
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 } else if ((cache->miscObjs != NULL) &&
2363 (cache->miscObjs->number != 0))
2364 {
2365 xmlXPathObjectPtr ret;
2366 /*
2367 * Fallback to misc-cache.
2368 */
2369 ret = (xmlXPathObjectPtr)
2370 cache->miscObjs->items[--cache->miscObjs->number];
2371
2372 ret->type = XPATH_STRING;
2373 ret->stringval = val;
2374#ifdef XP_DEBUG_OBJ_USAGE
2375 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2376#endif
2377 return(ret);
2378 }
2379 }
2380 return(xmlXPathWrapString(val));
2381}
2382
2383/**
2384 * xmlXPathCacheNewNodeSet:
2385 * @ctxt: the XPath context
2386 * @val: the NodePtr value
2387 *
2388 * This is the cached version of xmlXPathNewNodeSet().
2389 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2390 * it with the single Node @val
2391 *
2392 * Returns the created or reused object.
2393 */
2394static xmlXPathObjectPtr
2395xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2396{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002397 if ((ctxt != NULL) && (ctxt->cache)) {
2398 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002399
2400 if ((cache->nodesetObjs != NULL) &&
2401 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002402 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002403 xmlXPathObjectPtr ret;
2404 /*
2405 * Use the nodset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002406 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002407 ret = (xmlXPathObjectPtr)
2408 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2409 ret->type = XPATH_NODESET;
2410 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002411 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002412 if ((ret->nodesetval->nodeMax == 0) ||
2413 (val->type == XML_NAMESPACE_DECL))
2414 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002415 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002416 } else {
2417 ret->nodesetval->nodeTab[0] = val;
2418 ret->nodesetval->nodeNr = 1;
2419 }
2420 }
2421#ifdef XP_DEBUG_OBJ_USAGE
2422 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2423#endif
2424 return(ret);
2425 } else if ((cache->miscObjs != NULL) &&
2426 (cache->miscObjs->number != 0))
2427 {
2428 xmlXPathObjectPtr ret;
2429 /*
2430 * Fallback to misc-cache.
2431 */
2432
2433 ret = (xmlXPathObjectPtr)
2434 cache->miscObjs->items[--cache->miscObjs->number];
2435
2436 ret->type = XPATH_NODESET;
2437 ret->boolval = 0;
2438 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08002439 if (ret->nodesetval == NULL) {
2440 ctxt->lastError.domain = XML_FROM_XPATH;
2441 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2442 return(NULL);
2443 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002444#ifdef XP_DEBUG_OBJ_USAGE
2445 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2446#endif
2447 return(ret);
2448 }
2449 }
2450 return(xmlXPathNewNodeSet(val));
2451}
2452
2453/**
2454 * xmlXPathCacheNewCString:
2455 * @ctxt: the XPath context
2456 * @val: the char * value
2457 *
2458 * This is the cached version of xmlXPathNewCString().
2459 * Acquire an xmlXPathObjectPtr of type string and of value @val
2460 *
2461 * Returns the created or reused object.
2462 */
2463static xmlXPathObjectPtr
2464xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002465{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002466 if ((ctxt != NULL) && (ctxt->cache)) {
2467 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002468
2469 if ((cache->stringObjs != NULL) &&
2470 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002471 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002472 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002473
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002474 ret = (xmlXPathObjectPtr)
2475 cache->stringObjs->items[--cache->stringObjs->number];
2476
2477 ret->type = XPATH_STRING;
2478 ret->stringval = xmlStrdup(BAD_CAST val);
2479#ifdef XP_DEBUG_OBJ_USAGE
2480 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2481#endif
2482 return(ret);
2483 } else if ((cache->miscObjs != NULL) &&
2484 (cache->miscObjs->number != 0))
2485 {
2486 xmlXPathObjectPtr ret;
2487
2488 ret = (xmlXPathObjectPtr)
2489 cache->miscObjs->items[--cache->miscObjs->number];
2490
2491 ret->type = XPATH_STRING;
2492 ret->stringval = xmlStrdup(BAD_CAST val);
2493#ifdef XP_DEBUG_OBJ_USAGE
2494 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2495#endif
2496 return(ret);
2497 }
2498 }
2499 return(xmlXPathNewCString(val));
2500}
2501
2502/**
2503 * xmlXPathCacheNewString:
2504 * @ctxt: the XPath context
2505 * @val: the xmlChar * value
2506 *
2507 * This is the cached version of xmlXPathNewString().
2508 * Acquire an xmlXPathObjectPtr of type string and of value @val
2509 *
2510 * Returns the created or reused object.
2511 */
2512static xmlXPathObjectPtr
2513xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002514{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002515 if ((ctxt != NULL) && (ctxt->cache)) {
2516 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002517
2518 if ((cache->stringObjs != NULL) &&
2519 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002520 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002521 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002522
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002523 ret = (xmlXPathObjectPtr)
2524 cache->stringObjs->items[--cache->stringObjs->number];
2525 ret->type = XPATH_STRING;
2526 if (val != NULL)
2527 ret->stringval = xmlStrdup(val);
2528 else
2529 ret->stringval = xmlStrdup((const xmlChar *)"");
2530#ifdef XP_DEBUG_OBJ_USAGE
2531 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2532#endif
2533 return(ret);
2534 } else if ((cache->miscObjs != NULL) &&
2535 (cache->miscObjs->number != 0))
2536 {
2537 xmlXPathObjectPtr ret;
2538
2539 ret = (xmlXPathObjectPtr)
2540 cache->miscObjs->items[--cache->miscObjs->number];
2541
2542 ret->type = XPATH_STRING;
2543 if (val != NULL)
2544 ret->stringval = xmlStrdup(val);
2545 else
2546 ret->stringval = xmlStrdup((const xmlChar *)"");
2547#ifdef XP_DEBUG_OBJ_USAGE
2548 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2549#endif
2550 return(ret);
2551 }
2552 }
2553 return(xmlXPathNewString(val));
2554}
2555
2556/**
2557 * xmlXPathCacheNewBoolean:
2558 * @ctxt: the XPath context
2559 * @val: the boolean value
2560 *
2561 * This is the cached version of xmlXPathNewBoolean().
2562 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2563 *
2564 * Returns the created or reused object.
2565 */
2566static xmlXPathObjectPtr
2567xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002568{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002569 if ((ctxt != NULL) && (ctxt->cache)) {
2570 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002571
2572 if ((cache->booleanObjs != NULL) &&
2573 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002574 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002575 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002576
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002577 ret = (xmlXPathObjectPtr)
2578 cache->booleanObjs->items[--cache->booleanObjs->number];
2579 ret->type = XPATH_BOOLEAN;
2580 ret->boolval = (val != 0);
2581#ifdef XP_DEBUG_OBJ_USAGE
2582 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2583#endif
2584 return(ret);
2585 } else if ((cache->miscObjs != NULL) &&
2586 (cache->miscObjs->number != 0))
2587 {
2588 xmlXPathObjectPtr ret;
2589
2590 ret = (xmlXPathObjectPtr)
2591 cache->miscObjs->items[--cache->miscObjs->number];
2592
2593 ret->type = XPATH_BOOLEAN;
2594 ret->boolval = (val != 0);
2595#ifdef XP_DEBUG_OBJ_USAGE
2596 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2597#endif
2598 return(ret);
2599 }
2600 }
2601 return(xmlXPathNewBoolean(val));
2602}
2603
2604/**
2605 * xmlXPathCacheNewFloat:
2606 * @ctxt: the XPath context
2607 * @val: the double value
2608 *
2609 * This is the cached version of xmlXPathNewFloat().
2610 * Acquires an xmlXPathObjectPtr of type double and of value @val
2611 *
2612 * Returns the created or reused object.
2613 */
2614static xmlXPathObjectPtr
2615xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2616{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002617 if ((ctxt != NULL) && (ctxt->cache)) {
2618 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002619
2620 if ((cache->numberObjs != NULL) &&
2621 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002622 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002623 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002624
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002625 ret = (xmlXPathObjectPtr)
2626 cache->numberObjs->items[--cache->numberObjs->number];
2627 ret->type = XPATH_NUMBER;
2628 ret->floatval = val;
2629#ifdef XP_DEBUG_OBJ_USAGE
2630 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2631#endif
2632 return(ret);
2633 } else if ((cache->miscObjs != NULL) &&
2634 (cache->miscObjs->number != 0))
2635 {
2636 xmlXPathObjectPtr ret;
2637
2638 ret = (xmlXPathObjectPtr)
2639 cache->miscObjs->items[--cache->miscObjs->number];
2640
2641 ret->type = XPATH_NUMBER;
2642 ret->floatval = val;
2643#ifdef XP_DEBUG_OBJ_USAGE
2644 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2645#endif
2646 return(ret);
2647 }
2648 }
2649 return(xmlXPathNewFloat(val));
2650}
2651
2652/**
2653 * xmlXPathCacheConvertString:
2654 * @ctxt: the XPath context
2655 * @val: an XPath object
2656 *
2657 * This is the cached version of xmlXPathConvertString().
2658 * Converts an existing object to its string() equivalent
2659 *
2660 * Returns a created or reused object, the old one is freed (cached)
2661 * (or the operation is done directly on @val)
2662 */
2663
2664static xmlXPathObjectPtr
2665xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002666 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002667
2668 if (val == NULL)
2669 return(xmlXPathCacheNewCString(ctxt, ""));
2670
2671 switch (val->type) {
2672 case XPATH_UNDEFINED:
2673#ifdef DEBUG_EXPR
2674 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2675#endif
2676 break;
2677 case XPATH_NODESET:
2678 case XPATH_XSLT_TREE:
2679 res = xmlXPathCastNodeSetToString(val->nodesetval);
2680 break;
2681 case XPATH_STRING:
2682 return(val);
2683 case XPATH_BOOLEAN:
2684 res = xmlXPathCastBooleanToString(val->boolval);
2685 break;
2686 case XPATH_NUMBER:
2687 res = xmlXPathCastNumberToString(val->floatval);
2688 break;
2689 case XPATH_USERS:
2690 case XPATH_POINT:
2691 case XPATH_RANGE:
2692 case XPATH_LOCATIONSET:
2693 TODO;
2694 break;
2695 }
2696 xmlXPathReleaseObject(ctxt, val);
2697 if (res == NULL)
2698 return(xmlXPathCacheNewCString(ctxt, ""));
2699 return(xmlXPathCacheWrapString(ctxt, res));
2700}
2701
2702/**
2703 * xmlXPathCacheObjectCopy:
2704 * @ctxt: the XPath context
2705 * @val: the original object
2706 *
2707 * This is the cached version of xmlXPathObjectCopy().
2708 * Acquire a copy of a given object
2709 *
2710 * Returns a created or reused created object.
2711 */
2712static xmlXPathObjectPtr
2713xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2714{
2715 if (val == NULL)
2716 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002717
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002718 if (XP_HAS_CACHE(ctxt)) {
2719 switch (val->type) {
2720 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002721 return(xmlXPathCacheWrapNodeSet(ctxt,
2722 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002723 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002724 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002725 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002726 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002727 case XPATH_NUMBER:
2728 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2729 default:
2730 break;
2731 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002732 }
2733 return(xmlXPathObjectCopy(val));
2734}
2735
2736/**
2737 * xmlXPathCacheConvertBoolean:
2738 * @ctxt: the XPath context
2739 * @val: an XPath object
2740 *
2741 * This is the cached version of xmlXPathConvertBoolean().
2742 * Converts an existing object to its boolean() equivalent
2743 *
2744 * Returns a created or reused object, the old one is freed (or the operation
2745 * is done directly on @val)
2746 */
2747static xmlXPathObjectPtr
2748xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2749 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002750
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002751 if (val == NULL)
2752 return(xmlXPathCacheNewBoolean(ctxt, 0));
2753 if (val->type == XPATH_BOOLEAN)
2754 return(val);
2755 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2756 xmlXPathReleaseObject(ctxt, val);
2757 return(ret);
2758}
2759
2760/**
2761 * xmlXPathCacheConvertNumber:
2762 * @ctxt: the XPath context
2763 * @val: an XPath object
2764 *
2765 * This is the cached version of xmlXPathConvertNumber().
2766 * Converts an existing object to its number() equivalent
2767 *
2768 * Returns a created or reused object, the old one is freed (or the operation
2769 * is done directly on @val)
2770 */
2771static xmlXPathObjectPtr
2772xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2773 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002774
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002775 if (val == NULL)
2776 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2777 if (val->type == XPATH_NUMBER)
2778 return(val);
2779 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2780 xmlXPathReleaseObject(ctxt, val);
2781 return(ret);
2782}
2783
2784/************************************************************************
2785 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002786 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002787 * *
2788 ************************************************************************/
2789
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002790/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002791 * xmlXPathSetFrame:
2792 * @ctxt: an XPath parser context
2793 *
2794 * Set the callee evaluation frame
2795 *
2796 * Returns the previous frame value to be restored once done
2797 */
2798static int
2799xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2800 int ret;
2801
2802 if (ctxt == NULL)
2803 return(0);
2804 ret = ctxt->valueFrame;
2805 ctxt->valueFrame = ctxt->valueNr;
2806 return(ret);
2807}
2808
2809/**
2810 * xmlXPathPopFrame:
2811 * @ctxt: an XPath parser context
2812 * @frame: the previous frame value
2813 *
2814 * Remove the callee evaluation frame
2815 */
2816static void
2817xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2818 if (ctxt == NULL)
2819 return;
2820 if (ctxt->valueNr < ctxt->valueFrame) {
2821 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2822 }
2823 ctxt->valueFrame = frame;
2824}
2825
2826/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002827 * valuePop:
2828 * @ctxt: an XPath evaluation context
2829 *
2830 * Pops the top XPath object from the value stack
2831 *
2832 * Returns the XPath object just removed
2833 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002834xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002835valuePop(xmlXPathParserContextPtr ctxt)
2836{
2837 xmlXPathObjectPtr ret;
2838
Daniel Veillarda82b1822004-11-08 16:24:57 +00002839 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002840 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002841
2842 if (ctxt->valueNr <= ctxt->valueFrame) {
2843 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2844 return (NULL);
2845 }
2846
Daniel Veillard1c732d22002-11-30 11:22:59 +00002847 ctxt->valueNr--;
2848 if (ctxt->valueNr > 0)
2849 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2850 else
2851 ctxt->value = NULL;
2852 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002853 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002854 return (ret);
2855}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002856/**
2857 * valuePush:
2858 * @ctxt: an XPath evaluation context
2859 * @value: the XPath object
2860 *
2861 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002862 *
2863 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002864 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002865int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002866valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2867{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002868 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002869 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002870 xmlXPathObjectPtr *tmp;
2871
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002872 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2873 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2874 ctxt->error = XPATH_MEMORY_ERROR;
2875 return (0);
2876 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002877 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2878 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002879 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002880 if (tmp == NULL) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002881 xmlXPathErrMemory(NULL, "pushing value\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08002882 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002883 return (0);
2884 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002885 ctxt->valueMax *= 2;
2886 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002887 }
2888 ctxt->valueTab[ctxt->valueNr] = value;
2889 ctxt->value = value;
2890 return (ctxt->valueNr++);
2891}
Owen Taylor3473f882001-02-23 17:55:21 +00002892
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002893/**
2894 * xmlXPathPopBoolean:
2895 * @ctxt: an XPath parser context
2896 *
2897 * Pops a boolean from the stack, handling conversion if needed.
2898 * Check error with #xmlXPathCheckError.
2899 *
2900 * Returns the boolean
2901 */
2902int
2903xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2904 xmlXPathObjectPtr obj;
2905 int ret;
2906
2907 obj = valuePop(ctxt);
2908 if (obj == NULL) {
2909 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2910 return(0);
2911 }
William M. Brack08171912003-12-29 02:52:11 +00002912 if (obj->type != XPATH_BOOLEAN)
2913 ret = xmlXPathCastToBoolean(obj);
2914 else
2915 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002916 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002917 return(ret);
2918}
2919
2920/**
2921 * xmlXPathPopNumber:
2922 * @ctxt: an XPath parser context
2923 *
2924 * Pops a number from the stack, handling conversion if needed.
2925 * Check error with #xmlXPathCheckError.
2926 *
2927 * Returns the number
2928 */
2929double
2930xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2931 xmlXPathObjectPtr obj;
2932 double ret;
2933
2934 obj = valuePop(ctxt);
2935 if (obj == NULL) {
2936 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2937 return(0);
2938 }
William M. Brack08171912003-12-29 02:52:11 +00002939 if (obj->type != XPATH_NUMBER)
2940 ret = xmlXPathCastToNumber(obj);
2941 else
2942 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002943 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002944 return(ret);
2945}
2946
2947/**
2948 * xmlXPathPopString:
2949 * @ctxt: an XPath parser context
2950 *
2951 * Pops a string from the stack, handling conversion if needed.
2952 * Check error with #xmlXPathCheckError.
2953 *
2954 * Returns the string
2955 */
2956xmlChar *
2957xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2958 xmlXPathObjectPtr obj;
2959 xmlChar * ret;
2960
2961 obj = valuePop(ctxt);
2962 if (obj == NULL) {
2963 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2964 return(NULL);
2965 }
William M. Brack08171912003-12-29 02:52:11 +00002966 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002967 /* TODO: needs refactoring somewhere else */
2968 if (obj->stringval == ret)
2969 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002970 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002971 return(ret);
2972}
2973
2974/**
2975 * xmlXPathPopNodeSet:
2976 * @ctxt: an XPath parser context
2977 *
2978 * Pops a node-set from the stack, handling conversion if needed.
2979 * Check error with #xmlXPathCheckError.
2980 *
2981 * Returns the node-set
2982 */
2983xmlNodeSetPtr
2984xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2985 xmlXPathObjectPtr obj;
2986 xmlNodeSetPtr ret;
2987
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002988 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002989 if (ctxt->value == NULL) {
2990 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2991 return(NULL);
2992 }
2993 if (!xmlXPathStackIsNodeSet(ctxt)) {
2994 xmlXPathSetTypeError(ctxt);
2995 return(NULL);
2996 }
2997 obj = valuePop(ctxt);
2998 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002999#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00003000 /* to fix memory leak of not clearing obj->user */
3001 if (obj->boolval && obj->user != NULL)
3002 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003003#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003004 obj->nodesetval = NULL;
3005 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003006 return(ret);
3007}
3008
3009/**
3010 * xmlXPathPopExternal:
3011 * @ctxt: an XPath parser context
3012 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003013 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003014 * Check error with #xmlXPathCheckError.
3015 *
3016 * Returns the object
3017 */
3018void *
3019xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3020 xmlXPathObjectPtr obj;
3021 void * ret;
3022
Daniel Veillarda82b1822004-11-08 16:24:57 +00003023 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003024 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3025 return(NULL);
3026 }
3027 if (ctxt->value->type != XPATH_USERS) {
3028 xmlXPathSetTypeError(ctxt);
3029 return(NULL);
3030 }
3031 obj = valuePop(ctxt);
3032 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003033 obj->user = NULL;
3034 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003035 return(ret);
3036}
3037
Owen Taylor3473f882001-02-23 17:55:21 +00003038/*
3039 * Macros for accessing the content. Those should be used only by the parser,
3040 * and not exported.
3041 *
3042 * Dirty macros, i.e. one need to make assumption on the context to use them
3043 *
3044 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3045 * CUR returns the current xmlChar value, i.e. a 8 bit value
3046 * in ISO-Latin or UTF-8.
3047 * This should be used internally by the parser
3048 * only to compare to ASCII values otherwise it would break when
3049 * running with UTF-8 encoding.
3050 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3051 * to compare on ASCII based substring.
3052 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3053 * strings within the parser.
3054 * CURRENT Returns the current char value, with the full decoding of
3055 * UTF-8 if we are using this mode. It returns an int.
3056 * NEXT Skip to the next character, this does the proper decoding
3057 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3058 * It returns the pointer to the current xmlChar.
3059 */
3060
3061#define CUR (*ctxt->cur)
3062#define SKIP(val) ctxt->cur += (val)
3063#define NXT(val) ctxt->cur[(val)]
3064#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00003065#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3066
3067#define COPY_BUF(l,b,i,v) \
3068 if (l == 1) b[i++] = (xmlChar) v; \
3069 else i += xmlCopyChar(l,&b[i],v)
3070
3071#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00003072
Daniel Veillard45490ae2008-07-29 09:13:19 +00003073#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00003074 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00003075
3076#define CURRENT (*ctxt->cur)
3077#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3078
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003079
3080#ifndef DBL_DIG
3081#define DBL_DIG 16
3082#endif
3083#ifndef DBL_EPSILON
3084#define DBL_EPSILON 1E-9
3085#endif
3086
3087#define UPPER_DOUBLE 1E9
3088#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00003089#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003090
3091#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00003092#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003093#define EXPONENT_DIGITS (3 + 2)
3094
3095/**
3096 * xmlXPathFormatNumber:
3097 * @number: number to format
3098 * @buffer: output buffer
3099 * @buffersize: size of output buffer
3100 *
3101 * Convert the number into a string representation.
3102 */
3103static void
3104xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3105{
Daniel Veillardcda96922001-08-21 10:56:31 +00003106 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003107 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003108 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003109 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003110 break;
3111 case -1:
3112 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003113 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003114 break;
3115 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003116 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003117 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003118 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003119 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003120 snprintf(buffer, buffersize, "0");
Nick Wellnhofer7482f412017-06-01 22:00:19 +02003121 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3122 (number == (int) number)) {
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003123 char work[30];
3124 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00003125 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003126
3127 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003128 if (value == 0) {
3129 *ptr++ = '0';
3130 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00003131 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003132 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00003133 while ((*cur) && (ptr - buffer < buffersize)) {
3134 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003135 }
3136 }
3137 if (ptr - buffer < buffersize) {
3138 *ptr = 0;
3139 } else if (buffersize > 0) {
3140 ptr--;
3141 *ptr = 0;
3142 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003143 } else {
William M. Brackca797882007-05-11 14:45:53 +00003144 /*
3145 For the dimension of work,
3146 DBL_DIG is number of significant digits
3147 EXPONENT is only needed for "scientific notation"
3148 3 is sign, decimal point, and terminating zero
3149 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3150 Note that this dimension is slightly (a few characters)
3151 larger than actually necessary.
3152 */
3153 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003154 int integer_place, fraction_place;
3155 char *ptr;
3156 char *after_fraction;
3157 double absolute_value;
3158 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003159
Bjorn Reese70a9da52001-04-21 16:57:29 +00003160 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003161
Bjorn Reese70a9da52001-04-21 16:57:29 +00003162 /*
3163 * First choose format - scientific or regular floating point.
3164 * In either case, result is in work, and after_fraction points
3165 * just past the fractional part.
3166 */
3167 if ( ((absolute_value > UPPER_DOUBLE) ||
3168 (absolute_value < LOWER_DOUBLE)) &&
3169 (absolute_value != 0.0) ) {
3170 /* Use scientific notation */
3171 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3172 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003173 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00003174 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00003175 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003176
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003177 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003178 else {
3179 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00003180 if (absolute_value > 0.0) {
3181 integer_place = (int)log10(absolute_value);
3182 if (integer_place > 0)
3183 fraction_place = DBL_DIG - integer_place - 1;
3184 else
3185 fraction_place = DBL_DIG - integer_place;
3186 } else {
3187 fraction_place = 1;
3188 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003189 size = snprintf(work, sizeof(work), "%0.*f",
3190 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003191 }
3192
Daniel Veillardb9e4d5b2013-07-22 13:21:31 +08003193 /* Remove leading spaces sometimes inserted by snprintf */
3194 while (work[0] == ' ') {
3195 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3196 size--;
3197 }
3198
Bjorn Reese70a9da52001-04-21 16:57:29 +00003199 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00003200 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003201 ptr = after_fraction;
3202 while (*(--ptr) == '0')
3203 ;
3204 if (*ptr != '.')
3205 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003206 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003207
3208 /* Finally copy result back to caller */
3209 size = strlen(work) + 1;
3210 if (size > buffersize) {
3211 work[buffersize - 1] = 0;
3212 size = buffersize;
3213 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003214 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003215 }
3216 break;
3217 }
3218}
3219
Owen Taylor3473f882001-02-23 17:55:21 +00003220
3221/************************************************************************
3222 * *
3223 * Routines to handle NodeSets *
3224 * *
3225 ************************************************************************/
3226
3227/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003228 * xmlXPathOrderDocElems:
3229 * @doc: an input document
3230 *
3231 * Call this routine to speed up XPath computation on static documents.
3232 * This stamps all the element nodes with the document order
3233 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00003234 * field, the value stored is actually - the node number (starting at -1)
3235 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003236 *
William M. Brack08171912003-12-29 02:52:11 +00003237 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003238 * of error.
3239 */
3240long
3241xmlXPathOrderDocElems(xmlDocPtr doc) {
3242 long count = 0;
3243 xmlNodePtr cur;
3244
3245 if (doc == NULL)
3246 return(-1);
3247 cur = doc->children;
3248 while (cur != NULL) {
3249 if (cur->type == XML_ELEMENT_NODE) {
3250 cur->content = (void *) (-(++count));
3251 if (cur->children != NULL) {
3252 cur = cur->children;
3253 continue;
3254 }
3255 }
3256 if (cur->next != NULL) {
3257 cur = cur->next;
3258 continue;
3259 }
3260 do {
3261 cur = cur->parent;
3262 if (cur == NULL)
3263 break;
3264 if (cur == (xmlNodePtr) doc) {
3265 cur = NULL;
3266 break;
3267 }
3268 if (cur->next != NULL) {
3269 cur = cur->next;
3270 break;
3271 }
3272 } while (cur != NULL);
3273 }
3274 return(count);
3275}
3276
3277/**
Owen Taylor3473f882001-02-23 17:55:21 +00003278 * xmlXPathCmpNodes:
3279 * @node1: the first node
3280 * @node2: the second node
3281 *
3282 * Compare two nodes w.r.t document order
3283 *
3284 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00003285 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003286 */
3287int
3288xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3289 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003290 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003291 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003292 xmlNodePtr cur, root;
3293
3294 if ((node1 == NULL) || (node2 == NULL))
3295 return(-2);
3296 /*
3297 * a couple of optimizations which will avoid computations in most cases
3298 */
William M. Brackee0b9822007-03-07 08:15:01 +00003299 if (node1 == node2) /* trivial case */
3300 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00003301 if (node1->type == XML_ATTRIBUTE_NODE) {
3302 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003303 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003304 node1 = node1->parent;
3305 }
3306 if (node2->type == XML_ATTRIBUTE_NODE) {
3307 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003308 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003309 node2 = node2->parent;
3310 }
3311 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00003312 if (attr1 == attr2) {
3313 /* not required, but we keep attributes in order */
3314 if (attr1 != 0) {
3315 cur = attrNode2->prev;
3316 while (cur != NULL) {
3317 if (cur == attrNode1)
3318 return (1);
3319 cur = cur->prev;
3320 }
3321 return (-1);
3322 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003323 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00003324 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003325 if (attr2 == 1)
3326 return(1);
3327 return(-1);
3328 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003329 if ((node1->type == XML_NAMESPACE_DECL) ||
3330 (node2->type == XML_NAMESPACE_DECL))
3331 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003332 if (node1 == node2->prev)
3333 return(1);
3334 if (node1 == node2->next)
3335 return(-1);
3336
3337 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003338 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003339 */
3340 if ((node1->type == XML_ELEMENT_NODE) &&
3341 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003342 (0 > (long) node1->content) &&
3343 (0 > (long) node2->content) &&
3344 (node1->doc == node2->doc)) {
3345 long l1, l2;
3346
3347 l1 = -((long) node1->content);
3348 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003349 if (l1 < l2)
3350 return(1);
3351 if (l1 > l2)
3352 return(-1);
3353 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003354
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003355 /*
Owen Taylor3473f882001-02-23 17:55:21 +00003356 * compute depth to root
3357 */
3358 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003359 if (cur->parent == node1)
Owen Taylor3473f882001-02-23 17:55:21 +00003360 return(1);
3361 depth2++;
3362 }
3363 root = cur;
3364 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
Nick Wellnhofera0051992016-06-28 14:19:58 +02003365 if (cur->parent == node2)
Owen Taylor3473f882001-02-23 17:55:21 +00003366 return(-1);
3367 depth1++;
3368 }
3369 /*
3370 * Distinct document (or distinct entities :-( ) case.
3371 */
3372 if (root != cur) {
3373 return(-2);
3374 }
3375 /*
3376 * get the nearest common ancestor.
3377 */
3378 while (depth1 > depth2) {
3379 depth1--;
3380 node1 = node1->parent;
3381 }
3382 while (depth2 > depth1) {
3383 depth2--;
3384 node2 = node2->parent;
3385 }
3386 while (node1->parent != node2->parent) {
3387 node1 = node1->parent;
3388 node2 = node2->parent;
3389 /* should not happen but just in case ... */
3390 if ((node1 == NULL) || (node2 == NULL))
3391 return(-2);
3392 }
3393 /*
3394 * Find who's first.
3395 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003396 if (node1 == node2->prev)
3397 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003398 if (node1 == node2->next)
3399 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003400 /*
3401 * Speedup using document order if availble.
3402 */
3403 if ((node1->type == XML_ELEMENT_NODE) &&
3404 (node2->type == XML_ELEMENT_NODE) &&
3405 (0 > (long) node1->content) &&
3406 (0 > (long) node2->content) &&
3407 (node1->doc == node2->doc)) {
3408 long l1, l2;
3409
3410 l1 = -((long) node1->content);
3411 l2 = -((long) node2->content);
3412 if (l1 < l2)
3413 return(1);
3414 if (l1 > l2)
3415 return(-1);
3416 }
3417
Owen Taylor3473f882001-02-23 17:55:21 +00003418 for (cur = node1->next;cur != NULL;cur = cur->next)
3419 if (cur == node2)
3420 return(1);
3421 return(-1); /* assume there is no sibling list corruption */
3422}
3423
3424/**
3425 * xmlXPathNodeSetSort:
3426 * @set: the node set
3427 *
3428 * Sort the node set in document order
3429 */
3430void
3431xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Vojtech Fried3e031b72012-08-24 16:52:44 +08003432#ifndef WITH_TIM_SORT
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003433 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003434 xmlNodePtr tmp;
Vojtech Fried3e031b72012-08-24 16:52:44 +08003435#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003436
3437 if (set == NULL)
3438 return;
3439
Vojtech Fried3e031b72012-08-24 16:52:44 +08003440#ifndef WITH_TIM_SORT
3441 /*
3442 * Use the old Shell's sort implementation to sort the node-set
3443 * Timsort ought to be quite faster
3444 */
Owen Taylor3473f882001-02-23 17:55:21 +00003445 len = set->nodeNr;
3446 for (incr = len / 2; incr > 0; incr /= 2) {
3447 for (i = incr; i < len; i++) {
3448 j = i - incr;
3449 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003450#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003451 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3452 set->nodeTab[j + incr]) == -1)
3453#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003454 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003455 set->nodeTab[j + incr]) == -1)
3456#endif
3457 {
Owen Taylor3473f882001-02-23 17:55:21 +00003458 tmp = set->nodeTab[j];
3459 set->nodeTab[j] = set->nodeTab[j + incr];
3460 set->nodeTab[j + incr] = tmp;
3461 j -= incr;
3462 } else
3463 break;
3464 }
3465 }
3466 }
Vojtech Fried3e031b72012-08-24 16:52:44 +08003467#else /* WITH_TIM_SORT */
3468 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3469#endif /* WITH_TIM_SORT */
Owen Taylor3473f882001-02-23 17:55:21 +00003470}
3471
3472#define XML_NODESET_DEFAULT 10
3473/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003474 * xmlXPathNodeSetDupNs:
3475 * @node: the parent node of the namespace XPath node
3476 * @ns: the libxml namespace declaration node.
3477 *
3478 * Namespace node in libxml don't match the XPath semantic. In a node set
3479 * the namespace nodes are duplicated and the next pointer is set to the
3480 * parent node in the XPath semantic.
3481 *
3482 * Returns the newly created object.
3483 */
3484static xmlNodePtr
3485xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3486 xmlNsPtr cur;
3487
3488 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3489 return(NULL);
3490 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3491 return((xmlNodePtr) ns);
3492
3493 /*
3494 * Allocate a new Namespace and fill the fields.
3495 */
3496 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3497 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003498 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003499 return(NULL);
3500 }
3501 memset(cur, 0, sizeof(xmlNs));
3502 cur->type = XML_NAMESPACE_DECL;
3503 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003504 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003505 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003506 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003507 cur->next = (xmlNsPtr) node;
3508 return((xmlNodePtr) cur);
3509}
3510
3511/**
3512 * xmlXPathNodeSetFreeNs:
3513 * @ns: the XPath namespace node found in a nodeset.
3514 *
William M. Brack08171912003-12-29 02:52:11 +00003515 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003516 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003517 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003518 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003519void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003520xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3521 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3522 return;
3523
3524 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3525 if (ns->href != NULL)
3526 xmlFree((xmlChar *)ns->href);
3527 if (ns->prefix != NULL)
3528 xmlFree((xmlChar *)ns->prefix);
3529 xmlFree(ns);
3530 }
3531}
3532
3533/**
Owen Taylor3473f882001-02-23 17:55:21 +00003534 * xmlXPathNodeSetCreate:
3535 * @val: an initial xmlNodePtr, or NULL
3536 *
3537 * Create a new xmlNodeSetPtr of type double and of value @val
3538 *
3539 * Returns the newly created object.
3540 */
3541xmlNodeSetPtr
3542xmlXPathNodeSetCreate(xmlNodePtr val) {
3543 xmlNodeSetPtr ret;
3544
3545 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3546 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003547 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003548 return(NULL);
3549 }
3550 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3551 if (val != NULL) {
3552 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3553 sizeof(xmlNodePtr));
3554 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003555 xmlXPathErrMemory(NULL, "creating nodeset\n");
3556 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003557 return(NULL);
3558 }
3559 memset(ret->nodeTab, 0 ,
3560 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3561 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003562 if (val->type == XML_NAMESPACE_DECL) {
3563 xmlNsPtr ns = (xmlNsPtr) val;
3564
3565 ret->nodeTab[ret->nodeNr++] =
3566 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3567 } else
3568 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003569 }
3570 return(ret);
3571}
3572
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003573/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003574 * xmlXPathNodeSetCreateSize:
3575 * @size: the initial size of the set
3576 *
3577 * Create a new xmlNodeSetPtr of type double and of value @val
3578 *
3579 * Returns the newly created object.
3580 */
3581static xmlNodeSetPtr
3582xmlXPathNodeSetCreateSize(int size) {
3583 xmlNodeSetPtr ret;
3584
3585 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3586 if (ret == NULL) {
3587 xmlXPathErrMemory(NULL, "creating nodeset\n");
3588 return(NULL);
3589 }
3590 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3591 if (size < XML_NODESET_DEFAULT)
3592 size = XML_NODESET_DEFAULT;
3593 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3594 if (ret->nodeTab == NULL) {
3595 xmlXPathErrMemory(NULL, "creating nodeset\n");
3596 xmlFree(ret);
3597 return(NULL);
3598 }
3599 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003600 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003601 return(ret);
3602}
3603
3604/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003605 * xmlXPathNodeSetContains:
3606 * @cur: the node-set
3607 * @val: the node
3608 *
3609 * checks whether @cur contains @val
3610 *
3611 * Returns true (1) if @cur contains @val, false (0) otherwise
3612 */
3613int
3614xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3615 int i;
3616
Daniel Veillarda82b1822004-11-08 16:24:57 +00003617 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003618 if (val->type == XML_NAMESPACE_DECL) {
3619 for (i = 0; i < cur->nodeNr; i++) {
3620 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3621 xmlNsPtr ns1, ns2;
3622
3623 ns1 = (xmlNsPtr) val;
3624 ns2 = (xmlNsPtr) cur->nodeTab[i];
3625 if (ns1 == ns2)
3626 return(1);
3627 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3628 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3629 return(1);
3630 }
3631 }
3632 } else {
3633 for (i = 0; i < cur->nodeNr; i++) {
3634 if (cur->nodeTab[i] == val)
3635 return(1);
3636 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003637 }
3638 return(0);
3639}
3640
3641/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003642 * xmlXPathNodeSetAddNs:
3643 * @cur: the initial node set
3644 * @node: the hosting node
3645 * @ns: a the namespace node
3646 *
3647 * add a new namespace node to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003648 *
3649 * Returns 0 in case of success and -1 in case of error
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003650 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003651int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003652xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3653 int i;
3654
Daniel Veillard45490ae2008-07-29 09:13:19 +00003655
Daniel Veillarda82b1822004-11-08 16:24:57 +00003656 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3657 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003658 (node->type != XML_ELEMENT_NODE))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003659 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003660
William M. Brack08171912003-12-29 02:52:11 +00003661 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003662 /*
William M. Brack08171912003-12-29 02:52:11 +00003663 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003664 */
3665 for (i = 0;i < cur->nodeNr;i++) {
3666 if ((cur->nodeTab[i] != NULL) &&
3667 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003668 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003669 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003670 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003671 }
3672
3673 /*
3674 * grow the nodeTab if needed
3675 */
3676 if (cur->nodeMax == 0) {
3677 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3678 sizeof(xmlNodePtr));
3679 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003680 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003681 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003682 }
3683 memset(cur->nodeTab, 0 ,
3684 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3685 cur->nodeMax = XML_NODESET_DEFAULT;
3686 } else if (cur->nodeNr == cur->nodeMax) {
3687 xmlNodePtr *temp;
3688
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003689 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3690 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003691 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003692 }
Chris Evansd7958b22011-03-23 08:13:06 +08003693 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003694 sizeof(xmlNodePtr));
3695 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003696 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003697 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003698 }
Chris Evansd7958b22011-03-23 08:13:06 +08003699 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003700 cur->nodeTab = temp;
3701 }
3702 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003703 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003704}
3705
3706/**
Owen Taylor3473f882001-02-23 17:55:21 +00003707 * xmlXPathNodeSetAdd:
3708 * @cur: the initial node set
3709 * @val: a new xmlNodePtr
3710 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003711 * add a new xmlNodePtr to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003712 *
3713 * Returns 0 in case of success, and -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00003714 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003715int
Owen Taylor3473f882001-02-23 17:55:21 +00003716xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3717 int i;
3718
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003719 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003720
William M. Brack08171912003-12-29 02:52:11 +00003721 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003722 /*
Shlomi Fishd5bd2a92016-04-03 05:14:44 +03003723 * prevent duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003724 */
3725 for (i = 0;i < cur->nodeNr;i++)
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003726 if (cur->nodeTab[i] == val) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003727
3728 /*
3729 * grow the nodeTab if needed
3730 */
3731 if (cur->nodeMax == 0) {
3732 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3733 sizeof(xmlNodePtr));
3734 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003735 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003736 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003737 }
3738 memset(cur->nodeTab, 0 ,
3739 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3740 cur->nodeMax = XML_NODESET_DEFAULT;
3741 } else if (cur->nodeNr == cur->nodeMax) {
3742 xmlNodePtr *temp;
3743
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003744 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3745 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003746 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003747 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003748 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003749 sizeof(xmlNodePtr));
3750 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003751 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003752 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003753 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003754 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003755 cur->nodeTab = temp;
3756 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003757 if (val->type == XML_NAMESPACE_DECL) {
3758 xmlNsPtr ns = (xmlNsPtr) val;
3759
Daniel Veillard45490ae2008-07-29 09:13:19 +00003760 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003761 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3762 } else
3763 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003764 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003765}
3766
3767/**
3768 * xmlXPathNodeSetAddUnique:
3769 * @cur: the initial node set
3770 * @val: a new xmlNodePtr
3771 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003772 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003773 * when we are sure the node is not already in the set.
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003774 *
3775 * Returns 0 in case of success and -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00003776 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003777int
Owen Taylor3473f882001-02-23 17:55:21 +00003778xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003779 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003780
William M. Brack08171912003-12-29 02:52:11 +00003781 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003782 /*
3783 * grow the nodeTab if needed
3784 */
3785 if (cur->nodeMax == 0) {
3786 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3787 sizeof(xmlNodePtr));
3788 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003789 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003790 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003791 }
3792 memset(cur->nodeTab, 0 ,
3793 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3794 cur->nodeMax = XML_NODESET_DEFAULT;
3795 } else if (cur->nodeNr == cur->nodeMax) {
3796 xmlNodePtr *temp;
3797
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003798 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3799 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003800 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003801 }
Chris Evansd7958b22011-03-23 08:13:06 +08003802 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003803 sizeof(xmlNodePtr));
3804 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003805 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003806 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003807 }
3808 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003809 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003810 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003811 if (val->type == XML_NAMESPACE_DECL) {
3812 xmlNsPtr ns = (xmlNsPtr) val;
3813
Daniel Veillard45490ae2008-07-29 09:13:19 +00003814 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003815 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3816 } else
3817 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003818 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003819}
3820
3821/**
3822 * xmlXPathNodeSetMerge:
3823 * @val1: the first NodeSet or NULL
3824 * @val2: the second NodeSet
3825 *
3826 * Merges two nodesets, all nodes from @val2 are added to @val1
3827 * if @val1 is NULL, a new set is created and copied from @val2
3828 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003829 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003830 */
3831xmlNodeSetPtr
3832xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003833 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003834 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003835
3836 if (val2 == NULL) return(val1);
3837 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003838 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003839 if (val1 == NULL)
3840 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003841#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003842 /*
3843 * TODO: The optimization won't work in every case, since
3844 * those nasty namespace nodes need to be added with
3845 * xmlXPathNodeSetDupNs() to the set; thus a pure
3846 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003847 * If there was a flag on the nodesetval, indicating that
3848 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003849 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003850 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003851 * Optimization: Create an equally sized node-set
3852 * and memcpy the content.
3853 */
3854 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3855 if (val1 == NULL)
3856 return(NULL);
3857 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003858 if (val2->nodeNr == 1)
3859 *(val1->nodeTab) = *(val2->nodeTab);
3860 else {
3861 memcpy(val1->nodeTab, val2->nodeTab,
3862 val2->nodeNr * sizeof(xmlNodePtr));
3863 }
3864 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003865 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003866 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003867#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003868 }
3869
William M. Brack08171912003-12-29 02:52:11 +00003870 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003871 initNr = val1->nodeNr;
3872
3873 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003874 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003875 /*
William M. Brack08171912003-12-29 02:52:11 +00003876 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003877 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003878 skip = 0;
3879 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003880 n1 = val1->nodeTab[j];
3881 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003882 skip = 1;
3883 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003884 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003885 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003886 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3887 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3888 ((xmlNsPtr) n2)->prefix)))
3889 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003890 skip = 1;
3891 break;
3892 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003893 }
3894 }
3895 if (skip)
3896 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003897
3898 /*
3899 * grow the nodeTab if needed
3900 */
3901 if (val1->nodeMax == 0) {
3902 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3903 sizeof(xmlNodePtr));
3904 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003905 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003906 return(NULL);
3907 }
3908 memset(val1->nodeTab, 0 ,
3909 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3910 val1->nodeMax = XML_NODESET_DEFAULT;
3911 } else if (val1->nodeNr == val1->nodeMax) {
3912 xmlNodePtr *temp;
3913
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003914 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3915 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3916 return(NULL);
3917 }
Chris Evansd7958b22011-03-23 08:13:06 +08003918 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003919 sizeof(xmlNodePtr));
3920 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003921 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003922 return(NULL);
3923 }
3924 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003925 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003926 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003927 if (n2->type == XML_NAMESPACE_DECL) {
3928 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003929
3930 val1->nodeTab[val1->nodeNr++] =
3931 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3932 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003933 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003934 }
3935
3936 return(val1);
3937}
3938
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003939
3940/**
3941 * xmlXPathNodeSetMergeAndClear:
3942 * @set1: the first NodeSet or NULL
3943 * @set2: the second NodeSet
3944 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3945 *
3946 * Merges two nodesets, all nodes from @set2 are added to @set1
3947 * if @set1 is NULL, a new set is created and copied from @set2.
3948 * Checks for duplicate nodes. Clears set2.
3949 *
3950 * Returns @set1 once extended or NULL in case of error.
3951 */
3952static xmlNodeSetPtr
3953xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3954 int hasNullEntries)
3955{
3956 if ((set1 == NULL) && (hasNullEntries == 0)) {
3957 /*
3958 * Note that doing a memcpy of the list, namespace nodes are
3959 * just assigned to set1, since set2 is cleared anyway.
3960 */
3961 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3962 if (set1 == NULL)
3963 return(NULL);
3964 if (set2->nodeNr != 0) {
3965 memcpy(set1->nodeTab, set2->nodeTab,
3966 set2->nodeNr * sizeof(xmlNodePtr));
3967 set1->nodeNr = set2->nodeNr;
3968 }
3969 } else {
3970 int i, j, initNbSet1;
3971 xmlNodePtr n1, n2;
3972
3973 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003974 set1 = xmlXPathNodeSetCreate(NULL);
3975 if (set1 == NULL)
3976 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003977
Daniel Veillard45490ae2008-07-29 09:13:19 +00003978 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003979 for (i = 0;i < set2->nodeNr;i++) {
3980 n2 = set2->nodeTab[i];
3981 /*
3982 * Skip NULLed entries.
3983 */
3984 if (n2 == NULL)
3985 continue;
3986 /*
3987 * Skip duplicates.
3988 */
3989 for (j = 0; j < initNbSet1; j++) {
3990 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003991 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003992 goto skip_node;
3993 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3994 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003995 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003996 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3997 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3998 ((xmlNsPtr) n2)->prefix)))
3999 {
4000 /*
4001 * Free the namespace node.
4002 */
4003 set2->nodeTab[i] = NULL;
4004 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
4005 goto skip_node;
4006 }
4007 }
4008 }
4009 /*
4010 * grow the nodeTab if needed
4011 */
4012 if (set1->nodeMax == 0) {
4013 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4014 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4015 if (set1->nodeTab == NULL) {
4016 xmlXPathErrMemory(NULL, "merging nodeset\n");
4017 return(NULL);
4018 }
4019 memset(set1->nodeTab, 0,
4020 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4021 set1->nodeMax = XML_NODESET_DEFAULT;
4022 } else if (set1->nodeNr >= set1->nodeMax) {
4023 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004024
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004025 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4026 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4027 return(NULL);
4028 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004029 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004030 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004031 if (temp == NULL) {
4032 xmlXPathErrMemory(NULL, "merging nodeset\n");
4033 return(NULL);
4034 }
4035 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004036 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004037 }
Nick Wellnhofer9d08b342017-05-21 16:46:12 +02004038 set1->nodeTab[set1->nodeNr++] = n2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004039skip_node:
4040 {}
4041 }
4042 }
4043 set2->nodeNr = 0;
4044 return(set1);
4045}
4046
4047/**
4048 * xmlXPathNodeSetMergeAndClearNoDupls:
4049 * @set1: the first NodeSet or NULL
4050 * @set2: the second NodeSet
4051 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4052 *
4053 * Merges two nodesets, all nodes from @set2 are added to @set1
4054 * if @set1 is NULL, a new set is created and copied from @set2.
4055 * Doesn't chack for duplicate nodes. Clears set2.
4056 *
4057 * Returns @set1 once extended or NULL in case of error.
4058 */
4059static xmlNodeSetPtr
4060xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4061 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004062{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004063 if (set2 == NULL)
4064 return(set1);
4065 if ((set1 == NULL) && (hasNullEntries == 0)) {
4066 /*
4067 * Note that doing a memcpy of the list, namespace nodes are
4068 * just assigned to set1, since set2 is cleared anyway.
4069 */
4070 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4071 if (set1 == NULL)
4072 return(NULL);
4073 if (set2->nodeNr != 0) {
4074 memcpy(set1->nodeTab, set2->nodeTab,
4075 set2->nodeNr * sizeof(xmlNodePtr));
4076 set1->nodeNr = set2->nodeNr;
4077 }
4078 } else {
4079 int i;
4080 xmlNodePtr n2;
4081
4082 if (set1 == NULL)
4083 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004084 if (set1 == NULL)
4085 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004086
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004087 for (i = 0;i < set2->nodeNr;i++) {
4088 n2 = set2->nodeTab[i];
4089 /*
4090 * Skip NULLed entries.
4091 */
4092 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004093 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004094 if (set1->nodeMax == 0) {
4095 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4096 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4097 if (set1->nodeTab == NULL) {
4098 xmlXPathErrMemory(NULL, "merging nodeset\n");
4099 return(NULL);
4100 }
4101 memset(set1->nodeTab, 0,
4102 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4103 set1->nodeMax = XML_NODESET_DEFAULT;
4104 } else if (set1->nodeNr >= set1->nodeMax) {
4105 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004106
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004107 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4108 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4109 return(NULL);
4110 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004111 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004112 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004113 if (temp == NULL) {
4114 xmlXPathErrMemory(NULL, "merging nodeset\n");
4115 return(NULL);
4116 }
4117 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004118 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004119 }
4120 set1->nodeTab[set1->nodeNr++] = n2;
4121 }
4122 }
4123 set2->nodeNr = 0;
4124 return(set1);
4125}
Daniel Veillard75be0132002-03-13 10:03:35 +00004126
4127/**
Owen Taylor3473f882001-02-23 17:55:21 +00004128 * xmlXPathNodeSetDel:
4129 * @cur: the initial node set
4130 * @val: an xmlNodePtr
4131 *
4132 * Removes an xmlNodePtr from an existing NodeSet
4133 */
4134void
4135xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4136 int i;
4137
4138 if (cur == NULL) return;
4139 if (val == NULL) return;
4140
4141 /*
William M. Brack08171912003-12-29 02:52:11 +00004142 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004143 */
4144 for (i = 0;i < cur->nodeNr;i++)
4145 if (cur->nodeTab[i] == val) break;
4146
William M. Brack08171912003-12-29 02:52:11 +00004147 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004148#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004149 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004150 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4151 val->name);
4152#endif
4153 return;
4154 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004155 if ((cur->nodeTab[i] != NULL) &&
4156 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4157 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004158 cur->nodeNr--;
4159 for (;i < cur->nodeNr;i++)
4160 cur->nodeTab[i] = cur->nodeTab[i + 1];
4161 cur->nodeTab[cur->nodeNr] = NULL;
4162}
4163
4164/**
4165 * xmlXPathNodeSetRemove:
4166 * @cur: the initial node set
4167 * @val: the index to remove
4168 *
4169 * Removes an entry from an existing NodeSet list.
4170 */
4171void
4172xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4173 if (cur == NULL) return;
4174 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004175 if ((cur->nodeTab[val] != NULL) &&
4176 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4177 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004178 cur->nodeNr--;
4179 for (;val < cur->nodeNr;val++)
4180 cur->nodeTab[val] = cur->nodeTab[val + 1];
4181 cur->nodeTab[cur->nodeNr] = NULL;
4182}
4183
4184/**
4185 * xmlXPathFreeNodeSet:
4186 * @obj: the xmlNodeSetPtr to free
4187 *
4188 * Free the NodeSet compound (not the actual nodes !).
4189 */
4190void
4191xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4192 if (obj == NULL) return;
4193 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004194 int i;
4195
William M. Brack08171912003-12-29 02:52:11 +00004196 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004197 for (i = 0;i < obj->nodeNr;i++)
4198 if ((obj->nodeTab[i] != NULL) &&
4199 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4200 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004201 xmlFree(obj->nodeTab);
4202 }
Owen Taylor3473f882001-02-23 17:55:21 +00004203 xmlFree(obj);
4204}
4205
4206/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004207 * xmlXPathNodeSetClearFromPos:
4208 * @set: the node set to be cleared
4209 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004210 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004211 * Clears the list from temporary XPath objects (e.g. namespace nodes
4212 * are feed) starting with the entry at @pos, but does *not* free the list
4213 * itself. Sets the length of the list to @pos.
4214 */
4215static void
4216xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4217{
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004218 if ((set == NULL) || (pos >= set->nodeNr))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004219 return;
4220 else if ((hasNsNodes)) {
4221 int i;
4222 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004223
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004224 for (i = pos; i < set->nodeNr; i++) {
4225 node = set->nodeTab[i];
4226 if ((node != NULL) &&
4227 (node->type == XML_NAMESPACE_DECL))
4228 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004229 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004230 }
4231 set->nodeNr = pos;
4232}
4233
4234/**
Nick Wellnhofer95a92492017-05-21 15:18:58 +02004235 * xmlXPathNodeSetClear:
4236 * @set: the node set to clear
4237 *
4238 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4239 * are feed), but does *not* free the list itself. Sets the length of the
4240 * list to 0.
4241 */
4242static void
4243xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4244{
4245 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4246}
4247
4248/**
4249 * xmlXPathNodeSetKeepLast:
4250 * @set: the node set to be cleared
4251 *
4252 * Move the last node to the first position and clear temporary XPath objects
4253 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4254 * to 1.
4255 */
4256static void
4257xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4258{
4259 int i;
4260 xmlNodePtr node;
4261
4262 if ((set == NULL) || (set->nodeNr <= 1))
4263 return;
4264 for (i = 0; i < set->nodeNr - 1; i++) {
4265 node = set->nodeTab[i];
4266 if ((node != NULL) &&
4267 (node->type == XML_NAMESPACE_DECL))
4268 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4269 }
4270 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4271 set->nodeNr = 1;
4272}
4273
4274/**
Owen Taylor3473f882001-02-23 17:55:21 +00004275 * xmlXPathFreeValueTree:
4276 * @obj: the xmlNodeSetPtr to free
4277 *
4278 * Free the NodeSet compound and the actual tree, this is different
4279 * from xmlXPathFreeNodeSet()
4280 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004281static void
Owen Taylor3473f882001-02-23 17:55:21 +00004282xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4283 int i;
4284
4285 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004286
4287 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004288 for (i = 0;i < obj->nodeNr;i++) {
4289 if (obj->nodeTab[i] != NULL) {
4290 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4291 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4292 } else {
4293 xmlFreeNodeList(obj->nodeTab[i]);
4294 }
4295 }
4296 }
Owen Taylor3473f882001-02-23 17:55:21 +00004297 xmlFree(obj->nodeTab);
4298 }
Owen Taylor3473f882001-02-23 17:55:21 +00004299 xmlFree(obj);
4300}
4301
4302#if defined(DEBUG) || defined(DEBUG_STEP)
4303/**
4304 * xmlGenericErrorContextNodeSet:
4305 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004306 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004307 *
4308 * Quick display of a NodeSet
4309 */
4310void
4311xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4312 int i;
4313
4314 if (output == NULL) output = xmlGenericErrorContext;
4315 if (obj == NULL) {
4316 fprintf(output, "NodeSet == NULL !\n");
4317 return;
4318 }
4319 if (obj->nodeNr == 0) {
4320 fprintf(output, "NodeSet is empty\n");
4321 return;
4322 }
4323 if (obj->nodeTab == NULL) {
4324 fprintf(output, " nodeTab == NULL !\n");
4325 return;
4326 }
4327 for (i = 0; i < obj->nodeNr; i++) {
4328 if (obj->nodeTab[i] == NULL) {
4329 fprintf(output, " NULL !\n");
4330 return;
4331 }
4332 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4333 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4334 fprintf(output, " /");
4335 else if (obj->nodeTab[i]->name == NULL)
4336 fprintf(output, " noname!");
4337 else fprintf(output, " %s", obj->nodeTab[i]->name);
4338 }
4339 fprintf(output, "\n");
4340}
4341#endif
4342
4343/**
4344 * xmlXPathNewNodeSet:
4345 * @val: the NodePtr value
4346 *
4347 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4348 * it with the single Node @val
4349 *
4350 * Returns the newly created object.
4351 */
4352xmlXPathObjectPtr
4353xmlXPathNewNodeSet(xmlNodePtr val) {
4354 xmlXPathObjectPtr ret;
4355
4356 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4357 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004358 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004359 return(NULL);
4360 }
4361 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4362 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004363 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004364 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004365 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004366#ifdef XP_DEBUG_OBJ_USAGE
4367 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4368#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004369 return(ret);
4370}
4371
4372/**
4373 * xmlXPathNewValueTree:
4374 * @val: the NodePtr value
4375 *
4376 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4377 * it with the tree root @val
4378 *
4379 * Returns the newly created object.
4380 */
4381xmlXPathObjectPtr
4382xmlXPathNewValueTree(xmlNodePtr val) {
4383 xmlXPathObjectPtr ret;
4384
4385 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4386 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004387 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004388 return(NULL);
4389 }
4390 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4391 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004392 ret->boolval = 1;
4393 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004394 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004395#ifdef XP_DEBUG_OBJ_USAGE
4396 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4397#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004398 return(ret);
4399}
4400
4401/**
4402 * xmlXPathNewNodeSetList:
4403 * @val: an existing NodeSet
4404 *
4405 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4406 * it with the Nodeset @val
4407 *
4408 * Returns the newly created object.
4409 */
4410xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004411xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4412{
Owen Taylor3473f882001-02-23 17:55:21 +00004413 xmlXPathObjectPtr ret;
4414 int i;
4415
4416 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004417 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004418 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004419 ret = xmlXPathNewNodeSet(NULL);
4420 else {
4421 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004422 if (ret) {
4423 for (i = 1; i < val->nodeNr; ++i) {
4424 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4425 < 0) break;
4426 }
4427 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004428 }
Owen Taylor3473f882001-02-23 17:55:21 +00004429
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004430 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004431}
4432
4433/**
4434 * xmlXPathWrapNodeSet:
4435 * @val: the NodePtr value
4436 *
4437 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4438 *
4439 * Returns the newly created object.
4440 */
4441xmlXPathObjectPtr
4442xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4443 xmlXPathObjectPtr ret;
4444
4445 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4446 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004447 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004448 return(NULL);
4449 }
4450 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4451 ret->type = XPATH_NODESET;
4452 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004453#ifdef XP_DEBUG_OBJ_USAGE
4454 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4455#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004456 return(ret);
4457}
4458
4459/**
4460 * xmlXPathFreeNodeSetList:
4461 * @obj: an existing NodeSetList object
4462 *
4463 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4464 * the list contrary to xmlXPathFreeObject().
4465 */
4466void
4467xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4468 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004469#ifdef XP_DEBUG_OBJ_USAGE
4470 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4471#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004472 xmlFree(obj);
4473}
4474
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004475/**
4476 * xmlXPathDifference:
4477 * @nodes1: a node-set
4478 * @nodes2: a node-set
4479 *
4480 * Implements the EXSLT - Sets difference() function:
4481 * node-set set:difference (node-set, node-set)
4482 *
4483 * Returns the difference between the two node sets, or nodes1 if
4484 * nodes2 is empty
4485 */
4486xmlNodeSetPtr
4487xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4488 xmlNodeSetPtr ret;
4489 int i, l1;
4490 xmlNodePtr cur;
4491
4492 if (xmlXPathNodeSetIsEmpty(nodes2))
4493 return(nodes1);
4494
4495 ret = xmlXPathNodeSetCreate(NULL);
4496 if (xmlXPathNodeSetIsEmpty(nodes1))
4497 return(ret);
4498
4499 l1 = xmlXPathNodeSetGetLength(nodes1);
4500
4501 for (i = 0; i < l1; i++) {
4502 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004503 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4504 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4505 break;
4506 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004507 }
4508 return(ret);
4509}
4510
4511/**
4512 * xmlXPathIntersection:
4513 * @nodes1: a node-set
4514 * @nodes2: a node-set
4515 *
4516 * Implements the EXSLT - Sets intersection() function:
4517 * node-set set:intersection (node-set, node-set)
4518 *
4519 * Returns a node set comprising the nodes that are within both the
4520 * node sets passed as arguments
4521 */
4522xmlNodeSetPtr
4523xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4524 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4525 int i, l1;
4526 xmlNodePtr cur;
4527
Daniel Veillardf88d8492008-04-01 08:00:31 +00004528 if (ret == NULL)
4529 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004530 if (xmlXPathNodeSetIsEmpty(nodes1))
4531 return(ret);
4532 if (xmlXPathNodeSetIsEmpty(nodes2))
4533 return(ret);
4534
4535 l1 = xmlXPathNodeSetGetLength(nodes1);
4536
4537 for (i = 0; i < l1; i++) {
4538 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004539 if (xmlXPathNodeSetContains(nodes2, cur)) {
4540 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4541 break;
4542 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004543 }
4544 return(ret);
4545}
4546
4547/**
4548 * xmlXPathDistinctSorted:
4549 * @nodes: a node-set, sorted by document order
4550 *
4551 * Implements the EXSLT - Sets distinct() function:
4552 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004553 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004554 * Returns a subset of the nodes contained in @nodes, or @nodes if
4555 * it is empty
4556 */
4557xmlNodeSetPtr
4558xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4559 xmlNodeSetPtr ret;
4560 xmlHashTablePtr hash;
4561 int i, l;
4562 xmlChar * strval;
4563 xmlNodePtr cur;
4564
4565 if (xmlXPathNodeSetIsEmpty(nodes))
4566 return(nodes);
4567
4568 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004569 if (ret == NULL)
4570 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004571 l = xmlXPathNodeSetGetLength(nodes);
4572 hash = xmlHashCreate (l);
4573 for (i = 0; i < l; i++) {
4574 cur = xmlXPathNodeSetItem(nodes, i);
4575 strval = xmlXPathCastNodeToString(cur);
4576 if (xmlHashLookup(hash, strval) == NULL) {
4577 xmlHashAddEntry(hash, strval, strval);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004578 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4579 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004580 } else {
4581 xmlFree(strval);
4582 }
4583 }
4584 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4585 return(ret);
4586}
4587
4588/**
4589 * xmlXPathDistinct:
4590 * @nodes: a node-set
4591 *
4592 * Implements the EXSLT - Sets distinct() function:
4593 * node-set set:distinct (node-set)
4594 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4595 * is called with the sorted node-set
4596 *
4597 * Returns a subset of the nodes contained in @nodes, or @nodes if
4598 * it is empty
4599 */
4600xmlNodeSetPtr
4601xmlXPathDistinct (xmlNodeSetPtr nodes) {
4602 if (xmlXPathNodeSetIsEmpty(nodes))
4603 return(nodes);
4604
4605 xmlXPathNodeSetSort(nodes);
4606 return(xmlXPathDistinctSorted(nodes));
4607}
4608
4609/**
4610 * xmlXPathHasSameNodes:
4611 * @nodes1: a node-set
4612 * @nodes2: a node-set
4613 *
4614 * Implements the EXSLT - Sets has-same-nodes function:
4615 * boolean set:has-same-node(node-set, node-set)
4616 *
4617 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4618 * otherwise
4619 */
4620int
4621xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4622 int i, l;
4623 xmlNodePtr cur;
4624
4625 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4626 xmlXPathNodeSetIsEmpty(nodes2))
4627 return(0);
4628
4629 l = xmlXPathNodeSetGetLength(nodes1);
4630 for (i = 0; i < l; i++) {
4631 cur = xmlXPathNodeSetItem(nodes1, i);
4632 if (xmlXPathNodeSetContains(nodes2, cur))
4633 return(1);
4634 }
4635 return(0);
4636}
4637
4638/**
4639 * xmlXPathNodeLeadingSorted:
4640 * @nodes: a node-set, sorted by document order
4641 * @node: a node
4642 *
4643 * Implements the EXSLT - Sets leading() function:
4644 * node-set set:leading (node-set, node-set)
4645 *
4646 * Returns the nodes in @nodes that precede @node in document order,
4647 * @nodes if @node is NULL or an empty node-set if @nodes
4648 * doesn't contain @node
4649 */
4650xmlNodeSetPtr
4651xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4652 int i, l;
4653 xmlNodePtr cur;
4654 xmlNodeSetPtr ret;
4655
4656 if (node == NULL)
4657 return(nodes);
4658
4659 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004660 if (ret == NULL)
4661 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004662 if (xmlXPathNodeSetIsEmpty(nodes) ||
4663 (!xmlXPathNodeSetContains(nodes, node)))
4664 return(ret);
4665
4666 l = xmlXPathNodeSetGetLength(nodes);
4667 for (i = 0; i < l; i++) {
4668 cur = xmlXPathNodeSetItem(nodes, i);
4669 if (cur == node)
4670 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004671 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4672 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004673 }
4674 return(ret);
4675}
4676
4677/**
4678 * xmlXPathNodeLeading:
4679 * @nodes: a node-set
4680 * @node: a node
4681 *
4682 * Implements the EXSLT - Sets leading() function:
4683 * node-set set:leading (node-set, node-set)
4684 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4685 * is called.
4686 *
4687 * Returns the nodes in @nodes that precede @node in document order,
4688 * @nodes if @node is NULL or an empty node-set if @nodes
4689 * doesn't contain @node
4690 */
4691xmlNodeSetPtr
4692xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4693 xmlXPathNodeSetSort(nodes);
4694 return(xmlXPathNodeLeadingSorted(nodes, node));
4695}
4696
4697/**
4698 * xmlXPathLeadingSorted:
4699 * @nodes1: a node-set, sorted by document order
4700 * @nodes2: a node-set, sorted by document order
4701 *
4702 * Implements the EXSLT - Sets leading() function:
4703 * node-set set:leading (node-set, node-set)
4704 *
4705 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4706 * in document order, @nodes1 if @nodes2 is NULL or empty or
4707 * an empty node-set if @nodes1 doesn't contain @nodes2
4708 */
4709xmlNodeSetPtr
4710xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4711 if (xmlXPathNodeSetIsEmpty(nodes2))
4712 return(nodes1);
4713 return(xmlXPathNodeLeadingSorted(nodes1,
4714 xmlXPathNodeSetItem(nodes2, 1)));
4715}
4716
4717/**
4718 * xmlXPathLeading:
4719 * @nodes1: a node-set
4720 * @nodes2: a node-set
4721 *
4722 * Implements the EXSLT - Sets leading() function:
4723 * node-set set:leading (node-set, node-set)
4724 * @nodes1 and @nodes2 are sorted by document order, then
4725 * #exslSetsLeadingSorted is called.
4726 *
4727 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4728 * in document order, @nodes1 if @nodes2 is NULL or empty or
4729 * an empty node-set if @nodes1 doesn't contain @nodes2
4730 */
4731xmlNodeSetPtr
4732xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4733 if (xmlXPathNodeSetIsEmpty(nodes2))
4734 return(nodes1);
4735 if (xmlXPathNodeSetIsEmpty(nodes1))
4736 return(xmlXPathNodeSetCreate(NULL));
4737 xmlXPathNodeSetSort(nodes1);
4738 xmlXPathNodeSetSort(nodes2);
4739 return(xmlXPathNodeLeadingSorted(nodes1,
4740 xmlXPathNodeSetItem(nodes2, 1)));
4741}
4742
4743/**
4744 * xmlXPathNodeTrailingSorted:
4745 * @nodes: a node-set, sorted by document order
4746 * @node: a node
4747 *
4748 * Implements the EXSLT - Sets trailing() function:
4749 * node-set set:trailing (node-set, node-set)
4750 *
4751 * Returns the nodes in @nodes that follow @node in document order,
4752 * @nodes if @node is NULL or an empty node-set if @nodes
4753 * doesn't contain @node
4754 */
4755xmlNodeSetPtr
4756xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4757 int i, l;
4758 xmlNodePtr cur;
4759 xmlNodeSetPtr ret;
4760
4761 if (node == NULL)
4762 return(nodes);
4763
4764 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004765 if (ret == NULL)
4766 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004767 if (xmlXPathNodeSetIsEmpty(nodes) ||
4768 (!xmlXPathNodeSetContains(nodes, node)))
4769 return(ret);
4770
4771 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004772 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004773 cur = xmlXPathNodeSetItem(nodes, i);
4774 if (cur == node)
4775 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004776 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4777 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004778 }
William M. Brack97ac8192007-06-06 17:19:24 +00004779 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004780 return(ret);
4781}
4782
4783/**
4784 * xmlXPathNodeTrailing:
4785 * @nodes: a node-set
4786 * @node: a node
4787 *
4788 * Implements the EXSLT - Sets trailing() function:
4789 * node-set set:trailing (node-set, node-set)
4790 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4791 * is called.
4792 *
4793 * Returns the nodes in @nodes that follow @node in document order,
4794 * @nodes if @node is NULL or an empty node-set if @nodes
4795 * doesn't contain @node
4796 */
4797xmlNodeSetPtr
4798xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4799 xmlXPathNodeSetSort(nodes);
4800 return(xmlXPathNodeTrailingSorted(nodes, node));
4801}
4802
4803/**
4804 * xmlXPathTrailingSorted:
4805 * @nodes1: a node-set, sorted by document order
4806 * @nodes2: a node-set, sorted by document order
4807 *
4808 * Implements the EXSLT - Sets trailing() function:
4809 * node-set set:trailing (node-set, node-set)
4810 *
4811 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4812 * in document order, @nodes1 if @nodes2 is NULL or empty or
4813 * an empty node-set if @nodes1 doesn't contain @nodes2
4814 */
4815xmlNodeSetPtr
4816xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4817 if (xmlXPathNodeSetIsEmpty(nodes2))
4818 return(nodes1);
4819 return(xmlXPathNodeTrailingSorted(nodes1,
4820 xmlXPathNodeSetItem(nodes2, 0)));
4821}
4822
4823/**
4824 * xmlXPathTrailing:
4825 * @nodes1: a node-set
4826 * @nodes2: a node-set
4827 *
4828 * Implements the EXSLT - Sets trailing() function:
4829 * node-set set:trailing (node-set, node-set)
4830 * @nodes1 and @nodes2 are sorted by document order, then
4831 * #xmlXPathTrailingSorted is called.
4832 *
4833 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4834 * in document order, @nodes1 if @nodes2 is NULL or empty or
4835 * an empty node-set if @nodes1 doesn't contain @nodes2
4836 */
4837xmlNodeSetPtr
4838xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4839 if (xmlXPathNodeSetIsEmpty(nodes2))
4840 return(nodes1);
4841 if (xmlXPathNodeSetIsEmpty(nodes1))
4842 return(xmlXPathNodeSetCreate(NULL));
4843 xmlXPathNodeSetSort(nodes1);
4844 xmlXPathNodeSetSort(nodes2);
4845 return(xmlXPathNodeTrailingSorted(nodes1,
4846 xmlXPathNodeSetItem(nodes2, 0)));
4847}
4848
Owen Taylor3473f882001-02-23 17:55:21 +00004849/************************************************************************
4850 * *
4851 * Routines to handle extra functions *
4852 * *
4853 ************************************************************************/
4854
4855/**
4856 * xmlXPathRegisterFunc:
4857 * @ctxt: the XPath context
4858 * @name: the function name
4859 * @f: the function implementation or NULL
4860 *
4861 * Register a new function. If @f is NULL it unregisters the function
4862 *
4863 * Returns 0 in case of success, -1 in case of error
4864 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004865int
Owen Taylor3473f882001-02-23 17:55:21 +00004866xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4867 xmlXPathFunction f) {
4868 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4869}
4870
4871/**
4872 * xmlXPathRegisterFuncNS:
4873 * @ctxt: the XPath context
4874 * @name: the function name
4875 * @ns_uri: the function namespace URI
4876 * @f: the function implementation or NULL
4877 *
4878 * Register a new function. If @f is NULL it unregisters the function
4879 *
4880 * Returns 0 in case of success, -1 in case of error
4881 */
4882int
4883xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4884 const xmlChar *ns_uri, xmlXPathFunction f) {
4885 if (ctxt == NULL)
4886 return(-1);
4887 if (name == NULL)
4888 return(-1);
4889
4890 if (ctxt->funcHash == NULL)
4891 ctxt->funcHash = xmlHashCreate(0);
4892 if (ctxt->funcHash == NULL)
4893 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004894 if (f == NULL)
4895 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004896 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004897}
4898
4899/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004900 * xmlXPathRegisterFuncLookup:
4901 * @ctxt: the XPath context
4902 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004903 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004904 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004905 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004906 */
4907void
4908xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4909 xmlXPathFuncLookupFunc f,
4910 void *funcCtxt) {
4911 if (ctxt == NULL)
4912 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004913 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004914 ctxt->funcLookupData = funcCtxt;
4915}
4916
4917/**
Owen Taylor3473f882001-02-23 17:55:21 +00004918 * xmlXPathFunctionLookup:
4919 * @ctxt: the XPath context
4920 * @name: the function name
4921 *
4922 * Search in the Function array of the context for the given
4923 * function.
4924 *
4925 * Returns the xmlXPathFunction or NULL if not found
4926 */
4927xmlXPathFunction
4928xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004929 if (ctxt == NULL)
4930 return (NULL);
4931
4932 if (ctxt->funcLookupFunc != NULL) {
4933 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004934 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004935
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004936 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004937 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004938 if (ret != NULL)
4939 return(ret);
4940 }
Owen Taylor3473f882001-02-23 17:55:21 +00004941 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4942}
4943
4944/**
4945 * xmlXPathFunctionLookupNS:
4946 * @ctxt: the XPath context
4947 * @name: the function name
4948 * @ns_uri: the function namespace URI
4949 *
4950 * Search in the Function array of the context for the given
4951 * function.
4952 *
4953 * Returns the xmlXPathFunction or NULL if not found
4954 */
4955xmlXPathFunction
4956xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4957 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004958 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004959
Owen Taylor3473f882001-02-23 17:55:21 +00004960 if (ctxt == NULL)
4961 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004962 if (name == NULL)
4963 return(NULL);
4964
Thomas Broyerba4ad322001-07-26 16:55:21 +00004965 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004966 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004967
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004968 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004969 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004970 if (ret != NULL)
4971 return(ret);
4972 }
4973
4974 if (ctxt->funcHash == NULL)
4975 return(NULL);
4976
William M. Brackad0e67c2004-12-01 14:35:10 +00004977 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4978 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004979}
4980
4981/**
4982 * xmlXPathRegisteredFuncsCleanup:
4983 * @ctxt: the XPath context
4984 *
4985 * Cleanup the XPath context data associated to registered functions
4986 */
4987void
4988xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4989 if (ctxt == NULL)
4990 return;
4991
4992 xmlHashFree(ctxt->funcHash, NULL);
4993 ctxt->funcHash = NULL;
4994}
4995
4996/************************************************************************
4997 * *
William M. Brack08171912003-12-29 02:52:11 +00004998 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004999 * *
5000 ************************************************************************/
5001
5002/**
5003 * xmlXPathRegisterVariable:
5004 * @ctxt: the XPath context
5005 * @name: the variable name
5006 * @value: the variable value or NULL
5007 *
5008 * Register a new variable value. If @value is NULL it unregisters
5009 * the variable
5010 *
5011 * Returns 0 in case of success, -1 in case of error
5012 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00005013int
Owen Taylor3473f882001-02-23 17:55:21 +00005014xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5015 xmlXPathObjectPtr value) {
5016 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5017}
5018
5019/**
5020 * xmlXPathRegisterVariableNS:
5021 * @ctxt: the XPath context
5022 * @name: the variable name
5023 * @ns_uri: the variable namespace URI
5024 * @value: the variable value or NULL
5025 *
5026 * Register a new variable value. If @value is NULL it unregisters
5027 * the variable
5028 *
5029 * Returns 0 in case of success, -1 in case of error
5030 */
5031int
5032xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5033 const xmlChar *ns_uri,
5034 xmlXPathObjectPtr value) {
5035 if (ctxt == NULL)
5036 return(-1);
5037 if (name == NULL)
5038 return(-1);
5039
5040 if (ctxt->varHash == NULL)
5041 ctxt->varHash = xmlHashCreate(0);
5042 if (ctxt->varHash == NULL)
5043 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00005044 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005045 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00005046 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00005047 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5048 (void *) value,
5049 (xmlHashDeallocator)xmlXPathFreeObject));
5050}
5051
5052/**
5053 * xmlXPathRegisterVariableLookup:
5054 * @ctxt: the XPath context
5055 * @f: the lookup function
5056 * @data: the lookup data
5057 *
5058 * register an external mechanism to do variable lookup
5059 */
5060void
5061xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5062 xmlXPathVariableLookupFunc f, void *data) {
5063 if (ctxt == NULL)
5064 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00005065 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00005066 ctxt->varLookupData = data;
5067}
5068
5069/**
5070 * xmlXPathVariableLookup:
5071 * @ctxt: the XPath context
5072 * @name: the variable name
5073 *
5074 * Search in the Variable array of the context for the given
5075 * variable value.
5076 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005077 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005078 */
5079xmlXPathObjectPtr
5080xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5081 if (ctxt == NULL)
5082 return(NULL);
5083
5084 if (ctxt->varLookupFunc != NULL) {
5085 xmlXPathObjectPtr ret;
5086
5087 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5088 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00005089 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005090 }
5091 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5092}
5093
5094/**
5095 * xmlXPathVariableLookupNS:
5096 * @ctxt: the XPath context
5097 * @name: the variable name
5098 * @ns_uri: the variable namespace URI
5099 *
5100 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005101 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005102 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005103 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005104 */
5105xmlXPathObjectPtr
5106xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5107 const xmlChar *ns_uri) {
5108 if (ctxt == NULL)
5109 return(NULL);
5110
5111 if (ctxt->varLookupFunc != NULL) {
5112 xmlXPathObjectPtr ret;
5113
5114 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5115 (ctxt->varLookupData, name, ns_uri);
5116 if (ret != NULL) return(ret);
5117 }
5118
5119 if (ctxt->varHash == NULL)
5120 return(NULL);
5121 if (name == NULL)
5122 return(NULL);
5123
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005124 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005125 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005126}
5127
5128/**
5129 * xmlXPathRegisteredVariablesCleanup:
5130 * @ctxt: the XPath context
5131 *
5132 * Cleanup the XPath context data associated to registered variables
5133 */
5134void
5135xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5136 if (ctxt == NULL)
5137 return;
5138
Daniel Veillard76d66f42001-05-16 21:05:17 +00005139 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005140 ctxt->varHash = NULL;
5141}
5142
5143/**
5144 * xmlXPathRegisterNs:
5145 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005146 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005147 * @ns_uri: the namespace name
5148 *
5149 * Register a new namespace. If @ns_uri is NULL it unregisters
5150 * the namespace
5151 *
5152 * Returns 0 in case of success, -1 in case of error
5153 */
5154int
5155xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5156 const xmlChar *ns_uri) {
5157 if (ctxt == NULL)
5158 return(-1);
5159 if (prefix == NULL)
5160 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005161 if (prefix[0] == 0)
5162 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005163
5164 if (ctxt->nsHash == NULL)
5165 ctxt->nsHash = xmlHashCreate(10);
5166 if (ctxt->nsHash == NULL)
5167 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005168 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005169 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005170 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005171 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005172 (xmlHashDeallocator)xmlFree));
5173}
5174
5175/**
5176 * xmlXPathNsLookup:
5177 * @ctxt: the XPath context
5178 * @prefix: the namespace prefix value
5179 *
5180 * Search in the namespace declaration array of the context for the given
5181 * namespace name associated to the given prefix
5182 *
5183 * Returns the value or NULL if not found
5184 */
5185const xmlChar *
5186xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5187 if (ctxt == NULL)
5188 return(NULL);
5189 if (prefix == NULL)
5190 return(NULL);
5191
5192#ifdef XML_XML_NAMESPACE
5193 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5194 return(XML_XML_NAMESPACE);
5195#endif
5196
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005197 if (ctxt->namespaces != NULL) {
5198 int i;
5199
5200 for (i = 0;i < ctxt->nsNr;i++) {
5201 if ((ctxt->namespaces[i] != NULL) &&
5202 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5203 return(ctxt->namespaces[i]->href);
5204 }
5205 }
Owen Taylor3473f882001-02-23 17:55:21 +00005206
5207 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5208}
5209
5210/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005211 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005212 * @ctxt: the XPath context
5213 *
5214 * Cleanup the XPath context data associated to registered variables
5215 */
5216void
5217xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5218 if (ctxt == NULL)
5219 return;
5220
Daniel Veillard42766c02002-08-22 20:52:17 +00005221 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005222 ctxt->nsHash = NULL;
5223}
5224
5225/************************************************************************
5226 * *
5227 * Routines to handle Values *
5228 * *
5229 ************************************************************************/
5230
William M. Brack08171912003-12-29 02:52:11 +00005231/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005232
5233/**
5234 * xmlXPathNewFloat:
5235 * @val: the double value
5236 *
5237 * Create a new xmlXPathObjectPtr of type double and of value @val
5238 *
5239 * Returns the newly created object.
5240 */
5241xmlXPathObjectPtr
5242xmlXPathNewFloat(double val) {
5243 xmlXPathObjectPtr ret;
5244
5245 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5246 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005247 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005248 return(NULL);
5249 }
5250 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5251 ret->type = XPATH_NUMBER;
5252 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005253#ifdef XP_DEBUG_OBJ_USAGE
5254 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5255#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005256 return(ret);
5257}
5258
5259/**
5260 * xmlXPathNewBoolean:
5261 * @val: the boolean value
5262 *
5263 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5264 *
5265 * Returns the newly created object.
5266 */
5267xmlXPathObjectPtr
5268xmlXPathNewBoolean(int val) {
5269 xmlXPathObjectPtr ret;
5270
5271 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5272 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005273 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005274 return(NULL);
5275 }
5276 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5277 ret->type = XPATH_BOOLEAN;
5278 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005279#ifdef XP_DEBUG_OBJ_USAGE
5280 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5281#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005282 return(ret);
5283}
5284
5285/**
5286 * xmlXPathNewString:
5287 * @val: the xmlChar * value
5288 *
5289 * Create a new xmlXPathObjectPtr of type string and of value @val
5290 *
5291 * Returns the newly created object.
5292 */
5293xmlXPathObjectPtr
5294xmlXPathNewString(const xmlChar *val) {
5295 xmlXPathObjectPtr ret;
5296
5297 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5298 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005299 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005300 return(NULL);
5301 }
5302 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5303 ret->type = XPATH_STRING;
5304 if (val != NULL)
5305 ret->stringval = xmlStrdup(val);
5306 else
5307 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005308#ifdef XP_DEBUG_OBJ_USAGE
5309 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5310#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005311 return(ret);
5312}
5313
5314/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005315 * xmlXPathWrapString:
5316 * @val: the xmlChar * value
5317 *
5318 * Wraps the @val string into an XPath object.
5319 *
5320 * Returns the newly created object.
5321 */
5322xmlXPathObjectPtr
5323xmlXPathWrapString (xmlChar *val) {
5324 xmlXPathObjectPtr ret;
5325
5326 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5327 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005328 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005329 return(NULL);
5330 }
5331 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5332 ret->type = XPATH_STRING;
5333 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005334#ifdef XP_DEBUG_OBJ_USAGE
5335 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5336#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005337 return(ret);
5338}
5339
5340/**
Owen Taylor3473f882001-02-23 17:55:21 +00005341 * xmlXPathNewCString:
5342 * @val: the char * value
5343 *
5344 * Create a new xmlXPathObjectPtr of type string and of value @val
5345 *
5346 * Returns the newly created object.
5347 */
5348xmlXPathObjectPtr
5349xmlXPathNewCString(const char *val) {
5350 xmlXPathObjectPtr ret;
5351
5352 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5353 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005354 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005355 return(NULL);
5356 }
5357 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5358 ret->type = XPATH_STRING;
5359 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005360#ifdef XP_DEBUG_OBJ_USAGE
5361 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5362#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005363 return(ret);
5364}
5365
5366/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005367 * xmlXPathWrapCString:
5368 * @val: the char * value
5369 *
5370 * Wraps a string into an XPath object.
5371 *
5372 * Returns the newly created object.
5373 */
5374xmlXPathObjectPtr
5375xmlXPathWrapCString (char * val) {
5376 return(xmlXPathWrapString((xmlChar *)(val)));
5377}
5378
5379/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005380 * xmlXPathWrapExternal:
5381 * @val: the user data
5382 *
5383 * Wraps the @val data into an XPath object.
5384 *
5385 * Returns the newly created object.
5386 */
5387xmlXPathObjectPtr
5388xmlXPathWrapExternal (void *val) {
5389 xmlXPathObjectPtr ret;
5390
5391 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5392 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005393 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005394 return(NULL);
5395 }
5396 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5397 ret->type = XPATH_USERS;
5398 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005399#ifdef XP_DEBUG_OBJ_USAGE
5400 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5401#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005402 return(ret);
5403}
5404
5405/**
Owen Taylor3473f882001-02-23 17:55:21 +00005406 * xmlXPathObjectCopy:
5407 * @val: the original object
5408 *
5409 * allocate a new copy of a given object
5410 *
5411 * Returns the newly created object.
5412 */
5413xmlXPathObjectPtr
5414xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5415 xmlXPathObjectPtr ret;
5416
5417 if (val == NULL)
5418 return(NULL);
5419
5420 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5421 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005422 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005423 return(NULL);
5424 }
5425 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005426#ifdef XP_DEBUG_OBJ_USAGE
5427 xmlXPathDebugObjUsageRequested(NULL, val->type);
5428#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005429 switch (val->type) {
5430 case XPATH_BOOLEAN:
5431 case XPATH_NUMBER:
5432 case XPATH_POINT:
5433 case XPATH_RANGE:
5434 break;
5435 case XPATH_STRING:
5436 ret->stringval = xmlStrdup(val->stringval);
5437 break;
5438 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005439#if 0
5440/*
5441 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5442 this previous handling is no longer correct, and can cause some serious
5443 problems (ref. bug 145547)
5444*/
Owen Taylor3473f882001-02-23 17:55:21 +00005445 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005446 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005447 xmlNodePtr cur, tmp;
5448 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005449
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005450 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005451 top = xmlNewDoc(NULL);
5452 top->name = (char *)
5453 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005454 ret->user = top;
5455 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005456 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005457 cur = val->nodesetval->nodeTab[0]->children;
5458 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005459 tmp = xmlDocCopyNode(cur, top, 1);
5460 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005461 cur = cur->next;
5462 }
5463 }
William M. Bracke9449c52004-07-11 14:41:20 +00005464
Daniel Veillard9adc0462003-03-24 18:39:54 +00005465 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005466 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005467 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005468 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005469 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005470#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005471 case XPATH_NODESET:
5472 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005473 /* Do not deallocate the copied tree value */
5474 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005475 break;
5476 case XPATH_LOCATIONSET:
5477#ifdef LIBXML_XPTR_ENABLED
5478 {
5479 xmlLocationSetPtr loc = val->user;
5480 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5481 break;
5482 }
5483#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005484 case XPATH_USERS:
5485 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005486 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005487 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005488 xmlGenericError(xmlGenericErrorContext,
5489 "xmlXPathObjectCopy: unsupported type %d\n",
5490 val->type);
5491 break;
5492 }
5493 return(ret);
5494}
5495
5496/**
5497 * xmlXPathFreeObject:
5498 * @obj: the object to free
5499 *
5500 * Free up an xmlXPathObjectPtr object.
5501 */
5502void
5503xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5504 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005505 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005506 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005507#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005508 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005509 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005510 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005511 } else
5512#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005513 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005514 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005515 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005516 } else {
5517 if (obj->nodesetval != NULL)
5518 xmlXPathFreeNodeSet(obj->nodesetval);
5519 }
Owen Taylor3473f882001-02-23 17:55:21 +00005520#ifdef LIBXML_XPTR_ENABLED
5521 } else if (obj->type == XPATH_LOCATIONSET) {
5522 if (obj->user != NULL)
5523 xmlXPtrFreeLocationSet(obj->user);
5524#endif
5525 } else if (obj->type == XPATH_STRING) {
5526 if (obj->stringval != NULL)
5527 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005528 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005529#ifdef XP_DEBUG_OBJ_USAGE
5530 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5531#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005532 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005533}
Owen Taylor3473f882001-02-23 17:55:21 +00005534
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005535/**
5536 * xmlXPathReleaseObject:
5537 * @obj: the xmlXPathObjectPtr to free or to cache
5538 *
5539 * Depending on the state of the cache this frees the given
5540 * XPath object or stores it in the cache.
5541 */
5542static void
5543xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5544{
5545#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5546 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5547 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5548
5549#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5550
5551 if (obj == NULL)
5552 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005553 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005554 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005555 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005556 xmlXPathContextCachePtr cache =
5557 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005558
5559 switch (obj->type) {
5560 case XPATH_NODESET:
5561 case XPATH_XSLT_TREE:
5562 if (obj->nodesetval != NULL) {
5563 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005564 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005565 * It looks like the @boolval is used for
5566 * evaluation if this an XSLT Result Tree Fragment.
5567 * TODO: Check if this assumption is correct.
5568 */
5569 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5570 xmlXPathFreeValueTree(obj->nodesetval);
5571 obj->nodesetval = NULL;
5572 } else if ((obj->nodesetval->nodeMax <= 40) &&
5573 (XP_CACHE_WANTS(cache->nodesetObjs,
5574 cache->maxNodeset)))
5575 {
5576 XP_CACHE_ADD(cache->nodesetObjs, obj);
5577 goto obj_cached;
5578 } else {
5579 xmlXPathFreeNodeSet(obj->nodesetval);
5580 obj->nodesetval = NULL;
5581 }
5582 }
5583 break;
5584 case XPATH_STRING:
5585 if (obj->stringval != NULL)
5586 xmlFree(obj->stringval);
5587
5588 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5589 XP_CACHE_ADD(cache->stringObjs, obj);
5590 goto obj_cached;
5591 }
5592 break;
5593 case XPATH_BOOLEAN:
5594 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5595 XP_CACHE_ADD(cache->booleanObjs, obj);
5596 goto obj_cached;
5597 }
5598 break;
5599 case XPATH_NUMBER:
5600 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5601 XP_CACHE_ADD(cache->numberObjs, obj);
5602 goto obj_cached;
5603 }
5604 break;
5605#ifdef LIBXML_XPTR_ENABLED
5606 case XPATH_LOCATIONSET:
5607 if (obj->user != NULL) {
5608 xmlXPtrFreeLocationSet(obj->user);
5609 }
5610 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005611#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005612 default:
5613 goto free_obj;
5614 }
5615
5616 /*
5617 * Fallback to adding to the misc-objects slot.
5618 */
5619 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5620 XP_CACHE_ADD(cache->miscObjs, obj);
5621 } else
5622 goto free_obj;
5623
5624obj_cached:
5625
5626#ifdef XP_DEBUG_OBJ_USAGE
5627 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5628#endif
5629
5630 if (obj->nodesetval != NULL) {
5631 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005632
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005633 /*
5634 * TODO: Due to those nasty ns-nodes, we need to traverse
5635 * the list and free the ns-nodes.
5636 * URGENT TODO: Check if it's actually slowing things down.
5637 * Maybe we shouldn't try to preserve the list.
5638 */
5639 if (tmpset->nodeNr > 1) {
5640 int i;
5641 xmlNodePtr node;
5642
5643 for (i = 0; i < tmpset->nodeNr; i++) {
5644 node = tmpset->nodeTab[i];
5645 if ((node != NULL) &&
5646 (node->type == XML_NAMESPACE_DECL))
5647 {
5648 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5649 }
5650 }
5651 } else if (tmpset->nodeNr == 1) {
5652 if ((tmpset->nodeTab[0] != NULL) &&
5653 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5654 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005655 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005656 tmpset->nodeNr = 0;
5657 memset(obj, 0, sizeof(xmlXPathObject));
5658 obj->nodesetval = tmpset;
5659 } else
5660 memset(obj, 0, sizeof(xmlXPathObject));
5661
5662 return;
5663
5664free_obj:
5665 /*
5666 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005667 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005668 if (obj->nodesetval != NULL)
5669 xmlXPathFreeNodeSet(obj->nodesetval);
5670#ifdef XP_DEBUG_OBJ_USAGE
5671 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5672#endif
5673 xmlFree(obj);
5674 }
5675 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005676}
5677
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005678
5679/************************************************************************
5680 * *
5681 * Type Casting Routines *
5682 * *
5683 ************************************************************************/
5684
5685/**
5686 * xmlXPathCastBooleanToString:
5687 * @val: a boolean
5688 *
5689 * Converts a boolean to its string value.
5690 *
5691 * Returns a newly allocated string.
5692 */
5693xmlChar *
5694xmlXPathCastBooleanToString (int val) {
5695 xmlChar *ret;
5696 if (val)
5697 ret = xmlStrdup((const xmlChar *) "true");
5698 else
5699 ret = xmlStrdup((const xmlChar *) "false");
5700 return(ret);
5701}
5702
5703/**
5704 * xmlXPathCastNumberToString:
5705 * @val: a number
5706 *
5707 * Converts a number to its string value.
5708 *
5709 * Returns a newly allocated string.
5710 */
5711xmlChar *
5712xmlXPathCastNumberToString (double val) {
5713 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005714 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005715 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005716 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005717 break;
5718 case -1:
5719 ret = xmlStrdup((const xmlChar *) "-Infinity");
5720 break;
5721 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005722 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005723 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005724 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5725 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005726 } else {
5727 /* could be improved */
5728 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005729 xmlXPathFormatNumber(val, buf, 99);
5730 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005731 ret = xmlStrdup((const xmlChar *) buf);
5732 }
5733 }
5734 return(ret);
5735}
5736
5737/**
5738 * xmlXPathCastNodeToString:
5739 * @node: a node
5740 *
5741 * Converts a node to its string value.
5742 *
5743 * Returns a newly allocated string.
5744 */
5745xmlChar *
5746xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005747xmlChar *ret;
5748 if ((ret = xmlNodeGetContent(node)) == NULL)
5749 ret = xmlStrdup((const xmlChar *) "");
5750 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005751}
5752
5753/**
5754 * xmlXPathCastNodeSetToString:
5755 * @ns: a node-set
5756 *
5757 * Converts a node-set to its string value.
5758 *
5759 * Returns a newly allocated string.
5760 */
5761xmlChar *
5762xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5763 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5764 return(xmlStrdup((const xmlChar *) ""));
5765
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005766 if (ns->nodeNr > 1)
5767 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005768 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5769}
5770
5771/**
5772 * xmlXPathCastToString:
5773 * @val: an XPath object
5774 *
5775 * Converts an existing object to its string() equivalent
5776 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005777 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005778 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005779 */
5780xmlChar *
5781xmlXPathCastToString(xmlXPathObjectPtr val) {
5782 xmlChar *ret = NULL;
5783
5784 if (val == NULL)
5785 return(xmlStrdup((const xmlChar *) ""));
5786 switch (val->type) {
5787 case XPATH_UNDEFINED:
5788#ifdef DEBUG_EXPR
5789 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5790#endif
5791 ret = xmlStrdup((const xmlChar *) "");
5792 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005793 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005794 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005795 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5796 break;
5797 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005798 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005799 case XPATH_BOOLEAN:
5800 ret = xmlXPathCastBooleanToString(val->boolval);
5801 break;
5802 case XPATH_NUMBER: {
5803 ret = xmlXPathCastNumberToString(val->floatval);
5804 break;
5805 }
5806 case XPATH_USERS:
5807 case XPATH_POINT:
5808 case XPATH_RANGE:
5809 case XPATH_LOCATIONSET:
5810 TODO
5811 ret = xmlStrdup((const xmlChar *) "");
5812 break;
5813 }
5814 return(ret);
5815}
5816
5817/**
5818 * xmlXPathConvertString:
5819 * @val: an XPath object
5820 *
5821 * Converts an existing object to its string() equivalent
5822 *
5823 * Returns the new object, the old one is freed (or the operation
5824 * is done directly on @val)
5825 */
5826xmlXPathObjectPtr
5827xmlXPathConvertString(xmlXPathObjectPtr val) {
5828 xmlChar *res = NULL;
5829
5830 if (val == NULL)
5831 return(xmlXPathNewCString(""));
5832
5833 switch (val->type) {
5834 case XPATH_UNDEFINED:
5835#ifdef DEBUG_EXPR
5836 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5837#endif
5838 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005839 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005840 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005841 res = xmlXPathCastNodeSetToString(val->nodesetval);
5842 break;
5843 case XPATH_STRING:
5844 return(val);
5845 case XPATH_BOOLEAN:
5846 res = xmlXPathCastBooleanToString(val->boolval);
5847 break;
5848 case XPATH_NUMBER:
5849 res = xmlXPathCastNumberToString(val->floatval);
5850 break;
5851 case XPATH_USERS:
5852 case XPATH_POINT:
5853 case XPATH_RANGE:
5854 case XPATH_LOCATIONSET:
5855 TODO;
5856 break;
5857 }
5858 xmlXPathFreeObject(val);
5859 if (res == NULL)
5860 return(xmlXPathNewCString(""));
5861 return(xmlXPathWrapString(res));
5862}
5863
5864/**
5865 * xmlXPathCastBooleanToNumber:
5866 * @val: a boolean
5867 *
5868 * Converts a boolean to its number value
5869 *
5870 * Returns the number value
5871 */
5872double
5873xmlXPathCastBooleanToNumber(int val) {
5874 if (val)
5875 return(1.0);
5876 return(0.0);
5877}
5878
5879/**
5880 * xmlXPathCastStringToNumber:
5881 * @val: a string
5882 *
5883 * Converts a string to its number value
5884 *
5885 * Returns the number value
5886 */
5887double
5888xmlXPathCastStringToNumber(const xmlChar * val) {
5889 return(xmlXPathStringEvalNumber(val));
5890}
5891
5892/**
5893 * xmlXPathCastNodeToNumber:
5894 * @node: a node
5895 *
5896 * Converts a node to its number value
5897 *
5898 * Returns the number value
5899 */
5900double
5901xmlXPathCastNodeToNumber (xmlNodePtr node) {
5902 xmlChar *strval;
5903 double ret;
5904
5905 if (node == NULL)
5906 return(xmlXPathNAN);
5907 strval = xmlXPathCastNodeToString(node);
5908 if (strval == NULL)
5909 return(xmlXPathNAN);
5910 ret = xmlXPathCastStringToNumber(strval);
5911 xmlFree(strval);
5912
5913 return(ret);
5914}
5915
5916/**
5917 * xmlXPathCastNodeSetToNumber:
5918 * @ns: a node-set
5919 *
5920 * Converts a node-set to its number value
5921 *
5922 * Returns the number value
5923 */
5924double
5925xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5926 xmlChar *str;
5927 double ret;
5928
5929 if (ns == NULL)
5930 return(xmlXPathNAN);
5931 str = xmlXPathCastNodeSetToString(ns);
5932 ret = xmlXPathCastStringToNumber(str);
5933 xmlFree(str);
5934 return(ret);
5935}
5936
5937/**
5938 * xmlXPathCastToNumber:
5939 * @val: an XPath object
5940 *
5941 * Converts an XPath object to its number value
5942 *
5943 * Returns the number value
5944 */
5945double
5946xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5947 double ret = 0.0;
5948
5949 if (val == NULL)
5950 return(xmlXPathNAN);
5951 switch (val->type) {
5952 case XPATH_UNDEFINED:
5953#ifdef DEGUB_EXPR
5954 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5955#endif
5956 ret = xmlXPathNAN;
5957 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005958 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005959 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005960 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5961 break;
5962 case XPATH_STRING:
5963 ret = xmlXPathCastStringToNumber(val->stringval);
5964 break;
5965 case XPATH_NUMBER:
5966 ret = val->floatval;
5967 break;
5968 case XPATH_BOOLEAN:
5969 ret = xmlXPathCastBooleanToNumber(val->boolval);
5970 break;
5971 case XPATH_USERS:
5972 case XPATH_POINT:
5973 case XPATH_RANGE:
5974 case XPATH_LOCATIONSET:
5975 TODO;
5976 ret = xmlXPathNAN;
5977 break;
5978 }
5979 return(ret);
5980}
5981
5982/**
5983 * xmlXPathConvertNumber:
5984 * @val: an XPath object
5985 *
5986 * Converts an existing object to its number() equivalent
5987 *
5988 * Returns the new object, the old one is freed (or the operation
5989 * is done directly on @val)
5990 */
5991xmlXPathObjectPtr
5992xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5993 xmlXPathObjectPtr ret;
5994
5995 if (val == NULL)
5996 return(xmlXPathNewFloat(0.0));
5997 if (val->type == XPATH_NUMBER)
5998 return(val);
5999 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
6000 xmlXPathFreeObject(val);
6001 return(ret);
6002}
6003
6004/**
6005 * xmlXPathCastNumberToBoolean:
6006 * @val: a number
6007 *
6008 * Converts a number to its boolean value
6009 *
6010 * Returns the boolean value
6011 */
6012int
6013xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00006014 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006015 return(0);
6016 return(1);
6017}
6018
6019/**
6020 * xmlXPathCastStringToBoolean:
6021 * @val: a string
6022 *
6023 * Converts a string to its boolean value
6024 *
6025 * Returns the boolean value
6026 */
6027int
6028xmlXPathCastStringToBoolean (const xmlChar *val) {
6029 if ((val == NULL) || (xmlStrlen(val) == 0))
6030 return(0);
6031 return(1);
6032}
6033
6034/**
6035 * xmlXPathCastNodeSetToBoolean:
6036 * @ns: a node-set
6037 *
6038 * Converts a node-set to its boolean value
6039 *
6040 * Returns the boolean value
6041 */
6042int
6043xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6044 if ((ns == NULL) || (ns->nodeNr == 0))
6045 return(0);
6046 return(1);
6047}
6048
6049/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006050 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006051 * @val: an XPath object
6052 *
6053 * Converts an XPath object to its boolean value
6054 *
6055 * Returns the boolean value
6056 */
6057int
6058xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6059 int ret = 0;
6060
6061 if (val == NULL)
6062 return(0);
6063 switch (val->type) {
6064 case XPATH_UNDEFINED:
6065#ifdef DEBUG_EXPR
6066 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6067#endif
6068 ret = 0;
6069 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006070 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00006071 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006072 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6073 break;
6074 case XPATH_STRING:
6075 ret = xmlXPathCastStringToBoolean(val->stringval);
6076 break;
6077 case XPATH_NUMBER:
6078 ret = xmlXPathCastNumberToBoolean(val->floatval);
6079 break;
6080 case XPATH_BOOLEAN:
6081 ret = val->boolval;
6082 break;
6083 case XPATH_USERS:
6084 case XPATH_POINT:
6085 case XPATH_RANGE:
6086 case XPATH_LOCATIONSET:
6087 TODO;
6088 ret = 0;
6089 break;
6090 }
6091 return(ret);
6092}
6093
6094
6095/**
6096 * xmlXPathConvertBoolean:
6097 * @val: an XPath object
6098 *
6099 * Converts an existing object to its boolean() equivalent
6100 *
6101 * Returns the new object, the old one is freed (or the operation
6102 * is done directly on @val)
6103 */
6104xmlXPathObjectPtr
6105xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6106 xmlXPathObjectPtr ret;
6107
6108 if (val == NULL)
6109 return(xmlXPathNewBoolean(0));
6110 if (val->type == XPATH_BOOLEAN)
6111 return(val);
6112 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6113 xmlXPathFreeObject(val);
6114 return(ret);
6115}
6116
Owen Taylor3473f882001-02-23 17:55:21 +00006117/************************************************************************
6118 * *
6119 * Routines to handle XPath contexts *
6120 * *
6121 ************************************************************************/
6122
6123/**
6124 * xmlXPathNewContext:
6125 * @doc: the XML document
6126 *
6127 * Create a new xmlXPathContext
6128 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006129 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006130 */
6131xmlXPathContextPtr
6132xmlXPathNewContext(xmlDocPtr doc) {
6133 xmlXPathContextPtr ret;
6134
6135 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6136 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006137 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006138 return(NULL);
6139 }
6140 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6141 ret->doc = doc;
6142 ret->node = NULL;
6143
6144 ret->varHash = NULL;
6145
6146 ret->nb_types = 0;
6147 ret->max_types = 0;
6148 ret->types = NULL;
6149
6150 ret->funcHash = xmlHashCreate(0);
6151
6152 ret->nb_axis = 0;
6153 ret->max_axis = 0;
6154 ret->axis = NULL;
6155
6156 ret->nsHash = NULL;
6157 ret->user = NULL;
6158
6159 ret->contextSize = -1;
6160 ret->proximityPosition = -1;
6161
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006162#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006163 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006164 xmlXPathFreeContext(ret);
6165 return(NULL);
6166 }
6167#endif
6168
Daniel Veillard45490ae2008-07-29 09:13:19 +00006169 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006170
Owen Taylor3473f882001-02-23 17:55:21 +00006171 return(ret);
6172}
6173
6174/**
6175 * xmlXPathFreeContext:
6176 * @ctxt: the context to free
6177 *
6178 * Free up an xmlXPathContext
6179 */
6180void
6181xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006182 if (ctxt == NULL) return;
6183
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006184 if (ctxt->cache != NULL)
6185 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006186 xmlXPathRegisteredNsCleanup(ctxt);
6187 xmlXPathRegisteredFuncsCleanup(ctxt);
6188 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006189 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006190 xmlFree(ctxt);
6191}
6192
6193/************************************************************************
6194 * *
6195 * Routines to handle XPath parser contexts *
6196 * *
6197 ************************************************************************/
6198
6199#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006200 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006201 __xmlRaiseError(NULL, NULL, NULL, \
6202 NULL, NULL, XML_FROM_XPATH, \
6203 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6204 __FILE__, __LINE__, \
6205 NULL, NULL, NULL, 0, 0, \
6206 "NULL context pointer\n"); \
6207 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006208 } \
6209
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006210#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006211 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006212 __xmlRaiseError(NULL, NULL, NULL, \
6213 NULL, NULL, XML_FROM_XPATH, \
6214 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6215 __FILE__, __LINE__, \
6216 NULL, NULL, NULL, 0, 0, \
6217 "NULL context pointer\n"); \
6218 return(-1); \
6219 } \
6220
Owen Taylor3473f882001-02-23 17:55:21 +00006221
6222#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006223 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006224 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006225 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006226 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006227 }
Owen Taylor3473f882001-02-23 17:55:21 +00006228
6229
6230/**
6231 * xmlXPathNewParserContext:
6232 * @str: the XPath expression
6233 * @ctxt: the XPath context
6234 *
6235 * Create a new xmlXPathParserContext
6236 *
6237 * Returns the xmlXPathParserContext just allocated.
6238 */
6239xmlXPathParserContextPtr
6240xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6241 xmlXPathParserContextPtr ret;
6242
6243 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6244 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006245 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006246 return(NULL);
6247 }
6248 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6249 ret->cur = ret->base = str;
6250 ret->context = ctxt;
6251
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006252 ret->comp = xmlXPathNewCompExpr();
6253 if (ret->comp == NULL) {
6254 xmlFree(ret->valueTab);
6255 xmlFree(ret);
6256 return(NULL);
6257 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006258 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6259 ret->comp->dict = ctxt->dict;
6260 xmlDictReference(ret->comp->dict);
6261 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006262
6263 return(ret);
6264}
6265
6266/**
6267 * xmlXPathCompParserContext:
6268 * @comp: the XPath compiled expression
6269 * @ctxt: the XPath context
6270 *
6271 * Create a new xmlXPathParserContext when processing a compiled expression
6272 *
6273 * Returns the xmlXPathParserContext just allocated.
6274 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006275static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006276xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6277 xmlXPathParserContextPtr ret;
6278
6279 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6280 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006281 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006282 return(NULL);
6283 }
6284 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6285
Owen Taylor3473f882001-02-23 17:55:21 +00006286 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006287 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006288 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006289 if (ret->valueTab == NULL) {
6290 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006291 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006292 return(NULL);
6293 }
Owen Taylor3473f882001-02-23 17:55:21 +00006294 ret->valueNr = 0;
6295 ret->valueMax = 10;
6296 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006297 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006298
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006299 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006300 ret->comp = comp;
6301
Owen Taylor3473f882001-02-23 17:55:21 +00006302 return(ret);
6303}
6304
6305/**
6306 * xmlXPathFreeParserContext:
6307 * @ctxt: the context to free
6308 *
6309 * Free up an xmlXPathParserContext
6310 */
6311void
6312xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006313 int i;
6314
Owen Taylor3473f882001-02-23 17:55:21 +00006315 if (ctxt->valueTab != NULL) {
Nick Wellnhoferc8519702017-05-27 15:26:11 +02006316 for (i = 0; i < ctxt->valueNr; i++) {
6317 if (ctxt->context)
6318 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6319 else
6320 xmlXPathFreeObject(ctxt->valueTab[i]);
6321 }
Owen Taylor3473f882001-02-23 17:55:21 +00006322 xmlFree(ctxt->valueTab);
6323 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006324 if (ctxt->comp != NULL) {
6325#ifdef XPATH_STREAMING
6326 if (ctxt->comp->stream != NULL) {
6327 xmlFreePatternList(ctxt->comp->stream);
6328 ctxt->comp->stream = NULL;
6329 }
6330#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006331 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006332 }
Owen Taylor3473f882001-02-23 17:55:21 +00006333 xmlFree(ctxt);
6334}
6335
6336/************************************************************************
6337 * *
6338 * The implicit core function library *
6339 * *
6340 ************************************************************************/
6341
Owen Taylor3473f882001-02-23 17:55:21 +00006342/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006343 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006344 * @node: a node pointer
6345 *
6346 * Function computing the beginning of the string value of the node,
6347 * used to speed up comparisons
6348 *
6349 * Returns an int usable as a hash
6350 */
6351static unsigned int
6352xmlXPathNodeValHash(xmlNodePtr node) {
6353 int len = 2;
6354 const xmlChar * string = NULL;
6355 xmlNodePtr tmp = NULL;
6356 unsigned int ret = 0;
6357
6358 if (node == NULL)
6359 return(0);
6360
Daniel Veillard9adc0462003-03-24 18:39:54 +00006361 if (node->type == XML_DOCUMENT_NODE) {
6362 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6363 if (tmp == NULL)
6364 node = node->children;
6365 else
6366 node = tmp;
6367
6368 if (node == NULL)
6369 return(0);
6370 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006371
6372 switch (node->type) {
6373 case XML_COMMENT_NODE:
6374 case XML_PI_NODE:
6375 case XML_CDATA_SECTION_NODE:
6376 case XML_TEXT_NODE:
6377 string = node->content;
6378 if (string == NULL)
6379 return(0);
6380 if (string[0] == 0)
6381 return(0);
6382 return(((unsigned int) string[0]) +
6383 (((unsigned int) string[1]) << 8));
6384 case XML_NAMESPACE_DECL:
6385 string = ((xmlNsPtr)node)->href;
6386 if (string == NULL)
6387 return(0);
6388 if (string[0] == 0)
6389 return(0);
6390 return(((unsigned int) string[0]) +
6391 (((unsigned int) string[1]) << 8));
6392 case XML_ATTRIBUTE_NODE:
6393 tmp = ((xmlAttrPtr) node)->children;
6394 break;
6395 case XML_ELEMENT_NODE:
6396 tmp = node->children;
6397 break;
6398 default:
6399 return(0);
6400 }
6401 while (tmp != NULL) {
6402 switch (tmp->type) {
6403 case XML_COMMENT_NODE:
6404 case XML_PI_NODE:
6405 case XML_CDATA_SECTION_NODE:
6406 case XML_TEXT_NODE:
6407 string = tmp->content;
6408 break;
6409 case XML_NAMESPACE_DECL:
6410 string = ((xmlNsPtr)tmp)->href;
6411 break;
6412 default:
6413 break;
6414 }
6415 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006416 if (len == 1) {
6417 return(ret + (((unsigned int) string[0]) << 8));
6418 }
6419 if (string[1] == 0) {
6420 len = 1;
6421 ret = (unsigned int) string[0];
6422 } else {
6423 return(((unsigned int) string[0]) +
6424 (((unsigned int) string[1]) << 8));
6425 }
6426 }
6427 /*
6428 * Skip to next node
6429 */
6430 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6431 if (tmp->children->type != XML_ENTITY_DECL) {
6432 tmp = tmp->children;
6433 continue;
6434 }
6435 }
6436 if (tmp == node)
6437 break;
6438
6439 if (tmp->next != NULL) {
6440 tmp = tmp->next;
6441 continue;
6442 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006443
Daniel Veillardf06307e2001-07-03 10:35:50 +00006444 do {
6445 tmp = tmp->parent;
6446 if (tmp == NULL)
6447 break;
6448 if (tmp == node) {
6449 tmp = NULL;
6450 break;
6451 }
6452 if (tmp->next != NULL) {
6453 tmp = tmp->next;
6454 break;
6455 }
6456 } while (tmp != NULL);
6457 }
6458 return(ret);
6459}
6460
6461/**
6462 * xmlXPathStringHash:
6463 * @string: a string
6464 *
6465 * Function computing the beginning of the string value of the node,
6466 * used to speed up comparisons
6467 *
6468 * Returns an int usable as a hash
6469 */
6470static unsigned int
6471xmlXPathStringHash(const xmlChar * string) {
6472 if (string == NULL)
6473 return((unsigned int) 0);
6474 if (string[0] == 0)
6475 return(0);
6476 return(((unsigned int) string[0]) +
6477 (((unsigned int) string[1]) << 8));
6478}
6479
6480/**
Owen Taylor3473f882001-02-23 17:55:21 +00006481 * xmlXPathCompareNodeSetFloat:
6482 * @ctxt: the XPath Parser context
6483 * @inf: less than (1) or greater than (0)
6484 * @strict: is the comparison strict
6485 * @arg: the node set
6486 * @f: the value
6487 *
6488 * Implement the compare operation between a nodeset and a number
6489 * @ns < @val (1, 1, ...
6490 * @ns <= @val (1, 0, ...
6491 * @ns > @val (0, 1, ...
6492 * @ns >= @val (0, 0, ...
6493 *
6494 * If one object to be compared is a node-set and the other is a number,
6495 * then the comparison will be true if and only if there is a node in the
6496 * node-set such that the result of performing the comparison on the number
6497 * to be compared and on the result of converting the string-value of that
6498 * node to a number using the number function is true.
6499 *
6500 * Returns 0 or 1 depending on the results of the test.
6501 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006502static int
Owen Taylor3473f882001-02-23 17:55:21 +00006503xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6504 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6505 int i, ret = 0;
6506 xmlNodeSetPtr ns;
6507 xmlChar *str2;
6508
6509 if ((f == NULL) || (arg == NULL) ||
6510 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006511 xmlXPathReleaseObject(ctxt->context, arg);
6512 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006513 return(0);
6514 }
6515 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006516 if (ns != NULL) {
6517 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006518 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006519 if (str2 != NULL) {
6520 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006521 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006522 xmlFree(str2);
6523 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006524 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006525 ret = xmlXPathCompareValues(ctxt, inf, strict);
6526 if (ret)
6527 break;
6528 }
6529 }
Owen Taylor3473f882001-02-23 17:55:21 +00006530 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006531 xmlXPathReleaseObject(ctxt->context, arg);
6532 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006533 return(ret);
6534}
6535
6536/**
6537 * xmlXPathCompareNodeSetString:
6538 * @ctxt: the XPath Parser context
6539 * @inf: less than (1) or greater than (0)
6540 * @strict: is the comparison strict
6541 * @arg: the node set
6542 * @s: the value
6543 *
6544 * Implement the compare operation between a nodeset and a string
6545 * @ns < @val (1, 1, ...
6546 * @ns <= @val (1, 0, ...
6547 * @ns > @val (0, 1, ...
6548 * @ns >= @val (0, 0, ...
6549 *
6550 * If one object to be compared is a node-set and the other is a string,
6551 * then the comparison will be true if and only if there is a node in
6552 * the node-set such that the result of performing the comparison on the
6553 * string-value of the node and the other string is true.
6554 *
6555 * Returns 0 or 1 depending on the results of the test.
6556 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006557static int
Owen Taylor3473f882001-02-23 17:55:21 +00006558xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6559 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6560 int i, ret = 0;
6561 xmlNodeSetPtr ns;
6562 xmlChar *str2;
6563
6564 if ((s == NULL) || (arg == NULL) ||
6565 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006566 xmlXPathReleaseObject(ctxt->context, arg);
6567 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006568 return(0);
6569 }
6570 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006571 if (ns != NULL) {
6572 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006573 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006574 if (str2 != NULL) {
6575 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006576 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006577 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006578 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006579 ret = xmlXPathCompareValues(ctxt, inf, strict);
6580 if (ret)
6581 break;
6582 }
6583 }
Owen Taylor3473f882001-02-23 17:55:21 +00006584 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006585 xmlXPathReleaseObject(ctxt->context, arg);
6586 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006587 return(ret);
6588}
6589
6590/**
6591 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006592 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006593 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006594 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006595 * @arg2: the second node set object
6596 *
6597 * Implement the compare operation on nodesets:
6598 *
6599 * If both objects to be compared are node-sets, then the comparison
6600 * will be true if and only if there is a node in the first node-set
6601 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006602 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006603 * ....
6604 * When neither object to be compared is a node-set and the operator
6605 * is <=, <, >= or >, then the objects are compared by converting both
6606 * objects to numbers and comparing the numbers according to IEEE 754.
6607 * ....
6608 * The number function converts its argument to a number as follows:
6609 * - a string that consists of optional whitespace followed by an
6610 * optional minus sign followed by a Number followed by whitespace
6611 * is converted to the IEEE 754 number that is nearest (according
6612 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6613 * represented by the string; any other string is converted to NaN
6614 *
6615 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006616 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006617 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006618static int
6619xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006620 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6621 int i, j, init = 0;
6622 double val1;
6623 double *values2;
6624 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006625 xmlNodeSetPtr ns1;
6626 xmlNodeSetPtr ns2;
6627
6628 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006629 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6630 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006631 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006632 }
Owen Taylor3473f882001-02-23 17:55:21 +00006633 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006634 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6635 xmlXPathFreeObject(arg1);
6636 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006637 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006638 }
Owen Taylor3473f882001-02-23 17:55:21 +00006639
6640 ns1 = arg1->nodesetval;
6641 ns2 = arg2->nodesetval;
6642
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006643 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006644 xmlXPathFreeObject(arg1);
6645 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006646 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006647 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006648 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006649 xmlXPathFreeObject(arg1);
6650 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006651 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006652 }
Owen Taylor3473f882001-02-23 17:55:21 +00006653
6654 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6655 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006656 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006657 xmlXPathFreeObject(arg1);
6658 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006659 return(0);
6660 }
6661 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006662 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006663 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006664 continue;
6665 for (j = 0;j < ns2->nodeNr;j++) {
6666 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006667 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006668 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006669 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006670 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006671 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006672 ret = (val1 < values2[j]);
6673 else if (inf && !strict)
6674 ret = (val1 <= values2[j]);
6675 else if (!inf && strict)
6676 ret = (val1 > values2[j]);
6677 else if (!inf && !strict)
6678 ret = (val1 >= values2[j]);
6679 if (ret)
6680 break;
6681 }
6682 if (ret)
6683 break;
6684 init = 1;
6685 }
6686 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006687 xmlXPathFreeObject(arg1);
6688 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006689 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006690}
6691
6692/**
6693 * xmlXPathCompareNodeSetValue:
6694 * @ctxt: the XPath Parser context
6695 * @inf: less than (1) or greater than (0)
6696 * @strict: is the comparison strict
6697 * @arg: the node set
6698 * @val: the value
6699 *
6700 * Implement the compare operation between a nodeset and a value
6701 * @ns < @val (1, 1, ...
6702 * @ns <= @val (1, 0, ...
6703 * @ns > @val (0, 1, ...
6704 * @ns >= @val (0, 0, ...
6705 *
6706 * If one object to be compared is a node-set and the other is a boolean,
6707 * then the comparison will be true if and only if the result of performing
6708 * the comparison on the boolean and on the result of converting
6709 * the node-set to a boolean using the boolean function is true.
6710 *
6711 * Returns 0 or 1 depending on the results of the test.
6712 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006713static int
Owen Taylor3473f882001-02-23 17:55:21 +00006714xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6715 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6716 if ((val == NULL) || (arg == NULL) ||
6717 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6718 return(0);
6719
6720 switch(val->type) {
6721 case XPATH_NUMBER:
6722 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6723 case XPATH_NODESET:
6724 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006725 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006726 case XPATH_STRING:
6727 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6728 case XPATH_BOOLEAN:
6729 valuePush(ctxt, arg);
6730 xmlXPathBooleanFunction(ctxt, 1);
6731 valuePush(ctxt, val);
6732 return(xmlXPathCompareValues(ctxt, inf, strict));
6733 default:
Nick Wellnhofercf60dbe2017-05-25 16:20:56 +02006734 xmlGenericError(xmlGenericErrorContext,
6735 "xmlXPathCompareNodeSetValue: Can't compare node set "
6736 "and object of type %d\n",
6737 val->type);
6738 xmlXPathReleaseObject(ctxt->context, arg);
6739 xmlXPathReleaseObject(ctxt->context, val);
6740 XP_ERROR0(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006741 }
6742 return(0);
6743}
6744
6745/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006746 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006747 * @arg: the nodeset object argument
6748 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006749 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006750 *
6751 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6752 * If one object to be compared is a node-set and the other is a string,
6753 * then the comparison will be true if and only if there is a node in
6754 * the node-set such that the result of performing the comparison on the
6755 * string-value of the node and the other string is true.
6756 *
6757 * Returns 0 or 1 depending on the results of the test.
6758 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006759static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006760xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006761{
Owen Taylor3473f882001-02-23 17:55:21 +00006762 int i;
6763 xmlNodeSetPtr ns;
6764 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006765 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006766
6767 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006768 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6769 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006770 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006771 /*
6772 * A NULL nodeset compared with a string is always false
6773 * (since there is no node equal, and no node not equal)
6774 */
6775 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006776 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006777 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006778 for (i = 0; i < ns->nodeNr; i++) {
6779 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6780 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6781 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6782 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006783 if (neq)
6784 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006785 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006786 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6787 if (neq)
6788 continue;
6789 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006790 } else if (neq) {
6791 if (str2 != NULL)
6792 xmlFree(str2);
6793 return (1);
6794 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006795 if (str2 != NULL)
6796 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006797 } else if (neq)
6798 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006799 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006800 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006801}
6802
6803/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006804 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006805 * @arg: the nodeset object argument
6806 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006807 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006808 *
6809 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6810 * If one object to be compared is a node-set and the other is a number,
6811 * then the comparison will be true if and only if there is a node in
6812 * the node-set such that the result of performing the comparison on the
6813 * number to be compared and on the result of converting the string-value
6814 * of that node to a number using the number function is true.
6815 *
6816 * Returns 0 or 1 depending on the results of the test.
6817 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006818static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006819xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6820 xmlXPathObjectPtr arg, double f, int neq) {
6821 int i, ret=0;
6822 xmlNodeSetPtr ns;
6823 xmlChar *str2;
6824 xmlXPathObjectPtr val;
6825 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006826
6827 if ((arg == NULL) ||
6828 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6829 return(0);
6830
William M. Brack0c022ad2002-07-12 00:56:01 +00006831 ns = arg->nodesetval;
6832 if (ns != NULL) {
6833 for (i=0;i<ns->nodeNr;i++) {
6834 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6835 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006836 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006837 xmlFree(str2);
6838 xmlXPathNumberFunction(ctxt, 1);
6839 val = valuePop(ctxt);
6840 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006841 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006842 if (!xmlXPathIsNaN(v)) {
6843 if ((!neq) && (v==f)) {
6844 ret = 1;
6845 break;
6846 } else if ((neq) && (v!=f)) {
6847 ret = 1;
6848 break;
6849 }
William M. Brack32f0f712005-07-14 07:00:33 +00006850 } else { /* NaN is unequal to any value */
6851 if (neq)
6852 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006853 }
6854 }
6855 }
6856 }
6857
6858 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006859}
6860
6861
6862/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006863 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006864 * @arg1: first nodeset object argument
6865 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006866 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006867 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006868 * Implement the equal / not equal operation on XPath nodesets:
6869 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006870 * If both objects to be compared are node-sets, then the comparison
6871 * will be true if and only if there is a node in the first node-set and
6872 * a node in the second node-set such that the result of performing the
6873 * comparison on the string-values of the two nodes is true.
6874 *
6875 * (needless to say, this is a costly operation)
6876 *
6877 * Returns 0 or 1 depending on the results of the test.
6878 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006879static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006880xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006881 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006882 unsigned int *hashs1;
6883 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006884 xmlChar **values1;
6885 xmlChar **values2;
6886 int ret = 0;
6887 xmlNodeSetPtr ns1;
6888 xmlNodeSetPtr ns2;
6889
6890 if ((arg1 == NULL) ||
6891 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6892 return(0);
6893 if ((arg2 == NULL) ||
6894 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6895 return(0);
6896
6897 ns1 = arg1->nodesetval;
6898 ns2 = arg2->nodesetval;
6899
Daniel Veillard911f49a2001-04-07 15:39:35 +00006900 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006901 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006902 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006903 return(0);
6904
6905 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006906 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006907 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006908 if (neq == 0)
6909 for (i = 0;i < ns1->nodeNr;i++)
6910 for (j = 0;j < ns2->nodeNr;j++)
6911 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6912 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006913
6914 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006915 if (values1 == NULL) {
6916 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006917 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006918 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006919 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6920 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006921 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006922 xmlFree(values1);
6923 return(0);
6924 }
Owen Taylor3473f882001-02-23 17:55:21 +00006925 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6926 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6927 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006928 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006929 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006930 xmlFree(values1);
6931 return(0);
6932 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006933 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6934 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006935 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006936 xmlFree(hashs1);
6937 xmlFree(values1);
6938 xmlFree(values2);
6939 return(0);
6940 }
Owen Taylor3473f882001-02-23 17:55:21 +00006941 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6942 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006943 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006944 for (j = 0;j < ns2->nodeNr;j++) {
6945 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006946 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006947 if (hashs1[i] != hashs2[j]) {
6948 if (neq) {
6949 ret = 1;
6950 break;
6951 }
6952 }
6953 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006954 if (values1[i] == NULL)
6955 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6956 if (values2[j] == NULL)
6957 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006958 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006959 if (ret)
6960 break;
6961 }
Owen Taylor3473f882001-02-23 17:55:21 +00006962 }
6963 if (ret)
6964 break;
6965 }
6966 for (i = 0;i < ns1->nodeNr;i++)
6967 if (values1[i] != NULL)
6968 xmlFree(values1[i]);
6969 for (j = 0;j < ns2->nodeNr;j++)
6970 if (values2[j] != NULL)
6971 xmlFree(values2[j]);
6972 xmlFree(values1);
6973 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006974 xmlFree(hashs1);
6975 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006976 return(ret);
6977}
6978
William M. Brack0c022ad2002-07-12 00:56:01 +00006979static int
6980xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6981 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006982 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006983 /*
6984 *At this point we are assured neither arg1 nor arg2
6985 *is a nodeset, so we can just pick the appropriate routine.
6986 */
Owen Taylor3473f882001-02-23 17:55:21 +00006987 switch (arg1->type) {
6988 case XPATH_UNDEFINED:
6989#ifdef DEBUG_EXPR
6990 xmlGenericError(xmlGenericErrorContext,
6991 "Equal: undefined\n");
6992#endif
6993 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006994 case XPATH_BOOLEAN:
6995 switch (arg2->type) {
6996 case XPATH_UNDEFINED:
6997#ifdef DEBUG_EXPR
6998 xmlGenericError(xmlGenericErrorContext,
6999 "Equal: undefined\n");
7000#endif
7001 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007002 case XPATH_BOOLEAN:
7003#ifdef DEBUG_EXPR
7004 xmlGenericError(xmlGenericErrorContext,
7005 "Equal: %d boolean %d \n",
7006 arg1->boolval, arg2->boolval);
7007#endif
7008 ret = (arg1->boolval == arg2->boolval);
7009 break;
7010 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00007011 ret = (arg1->boolval ==
7012 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007013 break;
7014 case XPATH_STRING:
7015 if ((arg2->stringval == NULL) ||
7016 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007017 else
Owen Taylor3473f882001-02-23 17:55:21 +00007018 ret = 1;
7019 ret = (arg1->boolval == ret);
7020 break;
7021 case XPATH_USERS:
7022 case XPATH_POINT:
7023 case XPATH_RANGE:
7024 case XPATH_LOCATIONSET:
7025 TODO
7026 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007027 case XPATH_NODESET:
7028 case XPATH_XSLT_TREE:
7029 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007030 }
7031 break;
7032 case XPATH_NUMBER:
7033 switch (arg2->type) {
7034 case XPATH_UNDEFINED:
7035#ifdef DEBUG_EXPR
7036 xmlGenericError(xmlGenericErrorContext,
7037 "Equal: undefined\n");
7038#endif
7039 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007040 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00007041 ret = (arg2->boolval==
7042 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007043 break;
7044 case XPATH_STRING:
7045 valuePush(ctxt, arg2);
7046 xmlXPathNumberFunction(ctxt, 1);
7047 arg2 = valuePop(ctxt);
7048 /* no break on purpose */
7049 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007050 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007051 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007052 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007053 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007054 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7055 if (xmlXPathIsInf(arg2->floatval) == 1)
7056 ret = 1;
7057 else
7058 ret = 0;
7059 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7060 if (xmlXPathIsInf(arg2->floatval) == -1)
7061 ret = 1;
7062 else
7063 ret = 0;
7064 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7065 if (xmlXPathIsInf(arg1->floatval) == 1)
7066 ret = 1;
7067 else
7068 ret = 0;
7069 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7070 if (xmlXPathIsInf(arg1->floatval) == -1)
7071 ret = 1;
7072 else
7073 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007074 } else {
7075 ret = (arg1->floatval == arg2->floatval);
7076 }
Owen Taylor3473f882001-02-23 17:55:21 +00007077 break;
7078 case XPATH_USERS:
7079 case XPATH_POINT:
7080 case XPATH_RANGE:
7081 case XPATH_LOCATIONSET:
7082 TODO
7083 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007084 case XPATH_NODESET:
7085 case XPATH_XSLT_TREE:
7086 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007087 }
7088 break;
7089 case XPATH_STRING:
7090 switch (arg2->type) {
7091 case XPATH_UNDEFINED:
7092#ifdef DEBUG_EXPR
7093 xmlGenericError(xmlGenericErrorContext,
7094 "Equal: undefined\n");
7095#endif
7096 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007097 case XPATH_BOOLEAN:
7098 if ((arg1->stringval == NULL) ||
7099 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007100 else
Owen Taylor3473f882001-02-23 17:55:21 +00007101 ret = 1;
7102 ret = (arg2->boolval == ret);
7103 break;
7104 case XPATH_STRING:
7105 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7106 break;
7107 case XPATH_NUMBER:
7108 valuePush(ctxt, arg1);
7109 xmlXPathNumberFunction(ctxt, 1);
7110 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007111 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007112 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007113 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007114 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007115 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7116 if (xmlXPathIsInf(arg2->floatval) == 1)
7117 ret = 1;
7118 else
7119 ret = 0;
7120 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7121 if (xmlXPathIsInf(arg2->floatval) == -1)
7122 ret = 1;
7123 else
7124 ret = 0;
7125 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7126 if (xmlXPathIsInf(arg1->floatval) == 1)
7127 ret = 1;
7128 else
7129 ret = 0;
7130 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7131 if (xmlXPathIsInf(arg1->floatval) == -1)
7132 ret = 1;
7133 else
7134 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007135 } else {
7136 ret = (arg1->floatval == arg2->floatval);
7137 }
Owen Taylor3473f882001-02-23 17:55:21 +00007138 break;
7139 case XPATH_USERS:
7140 case XPATH_POINT:
7141 case XPATH_RANGE:
7142 case XPATH_LOCATIONSET:
7143 TODO
7144 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007145 case XPATH_NODESET:
7146 case XPATH_XSLT_TREE:
7147 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007148 }
7149 break;
7150 case XPATH_USERS:
7151 case XPATH_POINT:
7152 case XPATH_RANGE:
7153 case XPATH_LOCATIONSET:
7154 TODO
7155 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007156 case XPATH_NODESET:
7157 case XPATH_XSLT_TREE:
7158 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007159 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007160 xmlXPathReleaseObject(ctxt->context, arg1);
7161 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007162 return(ret);
7163}
7164
William M. Brack0c022ad2002-07-12 00:56:01 +00007165/**
7166 * xmlXPathEqualValues:
7167 * @ctxt: the XPath Parser context
7168 *
7169 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7170 *
7171 * Returns 0 or 1 depending on the results of the test.
7172 */
7173int
7174xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7175 xmlXPathObjectPtr arg1, arg2, argtmp;
7176 int ret = 0;
7177
Daniel Veillard6128c012004-11-08 17:16:15 +00007178 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007179 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007180 arg1 = valuePop(ctxt);
7181 if ((arg1 == NULL) || (arg2 == NULL)) {
7182 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007183 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007184 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007185 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007186 XP_ERROR0(XPATH_INVALID_OPERAND);
7187 }
7188
7189 if (arg1 == arg2) {
7190#ifdef DEBUG_EXPR
7191 xmlGenericError(xmlGenericErrorContext,
7192 "Equal: by pointer\n");
7193#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007194 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007195 return(1);
7196 }
7197
7198 /*
7199 *If either argument is a nodeset, it's a 'special case'
7200 */
7201 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7202 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7203 /*
7204 *Hack it to assure arg1 is the nodeset
7205 */
7206 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7207 argtmp = arg2;
7208 arg2 = arg1;
7209 arg1 = argtmp;
7210 }
7211 switch (arg2->type) {
7212 case XPATH_UNDEFINED:
7213#ifdef DEBUG_EXPR
7214 xmlGenericError(xmlGenericErrorContext,
7215 "Equal: undefined\n");
7216#endif
7217 break;
7218 case XPATH_NODESET:
7219 case XPATH_XSLT_TREE:
7220 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7221 break;
7222 case XPATH_BOOLEAN:
7223 if ((arg1->nodesetval == NULL) ||
7224 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007225 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007226 ret = 1;
7227 ret = (ret == arg2->boolval);
7228 break;
7229 case XPATH_NUMBER:
7230 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7231 break;
7232 case XPATH_STRING:
7233 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7234 break;
7235 case XPATH_USERS:
7236 case XPATH_POINT:
7237 case XPATH_RANGE:
7238 case XPATH_LOCATIONSET:
7239 TODO
7240 break;
7241 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007242 xmlXPathReleaseObject(ctxt->context, arg1);
7243 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007244 return(ret);
7245 }
7246
7247 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7248}
7249
7250/**
7251 * xmlXPathNotEqualValues:
7252 * @ctxt: the XPath Parser context
7253 *
7254 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7255 *
7256 * Returns 0 or 1 depending on the results of the test.
7257 */
7258int
7259xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7260 xmlXPathObjectPtr arg1, arg2, argtmp;
7261 int ret = 0;
7262
Daniel Veillard6128c012004-11-08 17:16:15 +00007263 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007264 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007265 arg1 = valuePop(ctxt);
7266 if ((arg1 == NULL) || (arg2 == NULL)) {
7267 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007268 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007269 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007270 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007271 XP_ERROR0(XPATH_INVALID_OPERAND);
7272 }
7273
7274 if (arg1 == arg2) {
7275#ifdef DEBUG_EXPR
7276 xmlGenericError(xmlGenericErrorContext,
7277 "NotEqual: by pointer\n");
7278#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007279 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007280 return(0);
7281 }
7282
7283 /*
7284 *If either argument is a nodeset, it's a 'special case'
7285 */
7286 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7287 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7288 /*
7289 *Hack it to assure arg1 is the nodeset
7290 */
7291 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7292 argtmp = arg2;
7293 arg2 = arg1;
7294 arg1 = argtmp;
7295 }
7296 switch (arg2->type) {
7297 case XPATH_UNDEFINED:
7298#ifdef DEBUG_EXPR
7299 xmlGenericError(xmlGenericErrorContext,
7300 "NotEqual: undefined\n");
7301#endif
7302 break;
7303 case XPATH_NODESET:
7304 case XPATH_XSLT_TREE:
7305 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7306 break;
7307 case XPATH_BOOLEAN:
7308 if ((arg1->nodesetval == NULL) ||
7309 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007310 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007311 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007312 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007313 break;
7314 case XPATH_NUMBER:
7315 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7316 break;
7317 case XPATH_STRING:
7318 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7319 break;
7320 case XPATH_USERS:
7321 case XPATH_POINT:
7322 case XPATH_RANGE:
7323 case XPATH_LOCATIONSET:
7324 TODO
7325 break;
7326 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007327 xmlXPathReleaseObject(ctxt->context, arg1);
7328 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007329 return(ret);
7330 }
7331
7332 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7333}
Owen Taylor3473f882001-02-23 17:55:21 +00007334
7335/**
7336 * xmlXPathCompareValues:
7337 * @ctxt: the XPath Parser context
7338 * @inf: less than (1) or greater than (0)
7339 * @strict: is the comparison strict
7340 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007341 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007342 * @arg1 < @arg2 (1, 1, ...
7343 * @arg1 <= @arg2 (1, 0, ...
7344 * @arg1 > @arg2 (0, 1, ...
7345 * @arg1 >= @arg2 (0, 0, ...
7346 *
7347 * When neither object to be compared is a node-set and the operator is
7348 * <=, <, >=, >, then the objects are compared by converted both objects
7349 * to numbers and comparing the numbers according to IEEE 754. The <
7350 * comparison will be true if and only if the first number is less than the
7351 * second number. The <= comparison will be true if and only if the first
7352 * number is less than or equal to the second number. The > comparison
7353 * will be true if and only if the first number is greater than the second
7354 * number. The >= comparison will be true if and only if the first number
7355 * is greater than or equal to the second number.
7356 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007357 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007358 */
7359int
7360xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007361 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007362 xmlXPathObjectPtr arg1, arg2;
7363
Daniel Veillard6128c012004-11-08 17:16:15 +00007364 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007365 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007366 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007367 if ((arg1 == NULL) || (arg2 == NULL)) {
7368 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007369 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007370 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007371 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007372 XP_ERROR0(XPATH_INVALID_OPERAND);
7373 }
7374
William M. Brack0c022ad2002-07-12 00:56:01 +00007375 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7376 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007377 /*
7378 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7379 * are not freed from within this routine; they will be freed from the
7380 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7381 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007382 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7383 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007384 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007385 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007386 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007387 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7388 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007389 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007390 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7391 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007392 }
7393 }
7394 return(ret);
7395 }
7396
7397 if (arg1->type != XPATH_NUMBER) {
7398 valuePush(ctxt, arg1);
7399 xmlXPathNumberFunction(ctxt, 1);
7400 arg1 = valuePop(ctxt);
7401 }
7402 if (arg1->type != XPATH_NUMBER) {
7403 xmlXPathFreeObject(arg1);
7404 xmlXPathFreeObject(arg2);
7405 XP_ERROR0(XPATH_INVALID_OPERAND);
7406 }
7407 if (arg2->type != XPATH_NUMBER) {
7408 valuePush(ctxt, arg2);
7409 xmlXPathNumberFunction(ctxt, 1);
7410 arg2 = valuePop(ctxt);
7411 }
7412 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007413 xmlXPathReleaseObject(ctxt->context, arg1);
7414 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007415 XP_ERROR0(XPATH_INVALID_OPERAND);
7416 }
7417 /*
7418 * Add tests for infinity and nan
7419 * => feedback on 3.4 for Inf and NaN
7420 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007421 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007422 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007423 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007424 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007425 arg1i=xmlXPathIsInf(arg1->floatval);
7426 arg2i=xmlXPathIsInf(arg2->floatval);
7427 if (inf && strict) {
7428 if ((arg1i == -1 && arg2i != -1) ||
7429 (arg2i == 1 && arg1i != 1)) {
7430 ret = 1;
7431 } else if (arg1i == 0 && arg2i == 0) {
7432 ret = (arg1->floatval < arg2->floatval);
7433 } else {
7434 ret = 0;
7435 }
7436 }
7437 else if (inf && !strict) {
7438 if (arg1i == -1 || arg2i == 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 (arg2i == -1 && arg1i != -1)) {
7449 ret = 1;
7450 } else if (arg1i == 0 && arg2i == 0) {
7451 ret = (arg1->floatval > arg2->floatval);
7452 } else {
7453 ret = 0;
7454 }
7455 }
7456 else if (!inf && !strict) {
7457 if (arg1i == 1 || arg2i == -1) {
7458 ret = 1;
7459 } else if (arg1i == 0 && arg2i == 0) {
7460 ret = (arg1->floatval >= arg2->floatval);
7461 } else {
7462 ret = 0;
7463 }
7464 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007465 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007466 xmlXPathReleaseObject(ctxt->context, arg1);
7467 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007468 return(ret);
7469}
7470
7471/**
7472 * xmlXPathValueFlipSign:
7473 * @ctxt: the XPath Parser context
7474 *
7475 * Implement the unary - operation on an XPath object
7476 * The numeric operators convert their operands to numbers as if
7477 * by calling the number function.
7478 */
7479void
7480xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007481 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007482 CAST_TO_NUMBER;
7483 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007484 if (xmlXPathIsNaN(ctxt->value->floatval))
7485 ctxt->value->floatval=xmlXPathNAN;
7486 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7487 ctxt->value->floatval=xmlXPathNINF;
7488 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7489 ctxt->value->floatval=xmlXPathPINF;
7490 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007491 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7492 ctxt->value->floatval = xmlXPathNZERO;
7493 else
7494 ctxt->value->floatval = 0;
7495 }
7496 else
7497 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007498}
7499
7500/**
7501 * xmlXPathAddValues:
7502 * @ctxt: the XPath Parser context
7503 *
7504 * Implement the add operation on XPath objects:
7505 * The numeric operators convert their operands to numbers as if
7506 * by calling the number function.
7507 */
7508void
7509xmlXPathAddValues(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 * xmlXPathSubValues:
7525 * @ctxt: the XPath Parser context
7526 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007527 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007528 * The numeric operators convert their operands to numbers as if
7529 * by calling the number function.
7530 */
7531void
7532xmlXPathSubValues(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 * xmlXPathMultValues:
7548 * @ctxt: the XPath Parser context
7549 *
7550 * Implement the multiply operation on XPath objects:
7551 * The numeric operators convert their operands to numbers as if
7552 * by calling the number function.
7553 */
7554void
7555xmlXPathMultValues(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);
7566 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007567}
7568
7569/**
7570 * xmlXPathDivValues:
7571 * @ctxt: the XPath Parser context
7572 *
7573 * Implement the div 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
7578xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7579 xmlXPathObjectPtr arg;
7580 double val;
7581
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007582 arg = valuePop(ctxt);
7583 if (arg == NULL)
7584 XP_ERROR(XPATH_INVALID_OPERAND);
7585 val = 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 Veillardeca82812002-04-24 11:42:02 +00007589 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7590 ctxt->value->floatval = xmlXPathNAN;
7591 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007592 if (ctxt->value->floatval == 0)
7593 ctxt->value->floatval = xmlXPathNAN;
7594 else if (ctxt->value->floatval > 0)
7595 ctxt->value->floatval = xmlXPathNINF;
7596 else if (ctxt->value->floatval < 0)
7597 ctxt->value->floatval = xmlXPathPINF;
7598 }
7599 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007600 if (ctxt->value->floatval == 0)
7601 ctxt->value->floatval = xmlXPathNAN;
7602 else if (ctxt->value->floatval > 0)
7603 ctxt->value->floatval = xmlXPathPINF;
7604 else if (ctxt->value->floatval < 0)
7605 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007606 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007607 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007608}
7609
7610/**
7611 * xmlXPathModValues:
7612 * @ctxt: the XPath Parser context
7613 *
7614 * Implement the mod operation on XPath objects: @arg1 / @arg2
7615 * The numeric operators convert their operands to numbers as if
7616 * by calling the number function.
7617 */
7618void
7619xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7620 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007621 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007622
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007623 arg = valuePop(ctxt);
7624 if (arg == NULL)
7625 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007626 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007627 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007628 CAST_TO_NUMBER;
7629 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007630 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007631 if (arg2 == 0)
7632 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007633 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007634 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007635 }
Owen Taylor3473f882001-02-23 17:55:21 +00007636}
7637
7638/************************************************************************
7639 * *
7640 * The traversal functions *
7641 * *
7642 ************************************************************************/
7643
Owen Taylor3473f882001-02-23 17:55:21 +00007644/*
7645 * A traversal function enumerates nodes along an axis.
7646 * Initially it must be called with NULL, and it indicates
7647 * termination on the axis by returning NULL.
7648 */
7649typedef xmlNodePtr (*xmlXPathTraversalFunction)
7650 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7651
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007652/*
7653 * xmlXPathTraversalFunctionExt:
7654 * A traversal function enumerates nodes along an axis.
7655 * Initially it must be called with NULL, and it indicates
7656 * termination on the axis by returning NULL.
7657 * The context node of the traversal is specified via @contextNode.
7658 */
7659typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7660 (xmlNodePtr cur, xmlNodePtr contextNode);
7661
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007662/*
7663 * xmlXPathNodeSetMergeFunction:
7664 * Used for merging node sets in xmlXPathCollectAndTest().
7665 */
7666typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7667 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7668
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007669
Owen Taylor3473f882001-02-23 17:55:21 +00007670/**
7671 * xmlXPathNextSelf:
7672 * @ctxt: the XPath Parser context
7673 * @cur: the current node in the traversal
7674 *
7675 * Traversal function for the "self" direction
7676 * The self axis contains just the context node itself
7677 *
7678 * Returns the next element following that axis
7679 */
7680xmlNodePtr
7681xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007682 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007683 if (cur == NULL)
7684 return(ctxt->context->node);
7685 return(NULL);
7686}
7687
7688/**
7689 * xmlXPathNextChild:
7690 * @ctxt: the XPath Parser context
7691 * @cur: the current node in the traversal
7692 *
7693 * Traversal function for the "child" direction
7694 * The child axis contains the children of the context node in document order.
7695 *
7696 * Returns the next element following that axis
7697 */
7698xmlNodePtr
7699xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007700 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007701 if (cur == NULL) {
7702 if (ctxt->context->node == NULL) return(NULL);
7703 switch (ctxt->context->node->type) {
7704 case XML_ELEMENT_NODE:
7705 case XML_TEXT_NODE:
7706 case XML_CDATA_SECTION_NODE:
7707 case XML_ENTITY_REF_NODE:
7708 case XML_ENTITY_NODE:
7709 case XML_PI_NODE:
7710 case XML_COMMENT_NODE:
7711 case XML_NOTATION_NODE:
7712 case XML_DTD_NODE:
7713 return(ctxt->context->node->children);
7714 case XML_DOCUMENT_NODE:
7715 case XML_DOCUMENT_TYPE_NODE:
7716 case XML_DOCUMENT_FRAG_NODE:
7717 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007718#ifdef LIBXML_DOCB_ENABLED
7719 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007720#endif
7721 return(((xmlDocPtr) ctxt->context->node)->children);
7722 case XML_ELEMENT_DECL:
7723 case XML_ATTRIBUTE_DECL:
7724 case XML_ENTITY_DECL:
7725 case XML_ATTRIBUTE_NODE:
7726 case XML_NAMESPACE_DECL:
7727 case XML_XINCLUDE_START:
7728 case XML_XINCLUDE_END:
7729 return(NULL);
7730 }
7731 return(NULL);
7732 }
7733 if ((cur->type == XML_DOCUMENT_NODE) ||
7734 (cur->type == XML_HTML_DOCUMENT_NODE))
7735 return(NULL);
7736 return(cur->next);
7737}
7738
7739/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007740 * xmlXPathNextChildElement:
7741 * @ctxt: the XPath Parser context
7742 * @cur: the current node in the traversal
7743 *
7744 * Traversal function for the "child" direction and nodes of type element.
7745 * The child axis contains the children of the context node in document order.
7746 *
7747 * Returns the next element following that axis
7748 */
7749static xmlNodePtr
7750xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7751 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7752 if (cur == NULL) {
7753 cur = ctxt->context->node;
7754 if (cur == NULL) return(NULL);
7755 /*
7756 * Get the first element child.
7757 */
7758 switch (cur->type) {
7759 case XML_ELEMENT_NODE:
7760 case XML_DOCUMENT_FRAG_NODE:
7761 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7762 case XML_ENTITY_NODE:
7763 cur = cur->children;
7764 if (cur != NULL) {
7765 if (cur->type == XML_ELEMENT_NODE)
7766 return(cur);
7767 do {
7768 cur = cur->next;
7769 } while ((cur != NULL) &&
7770 (cur->type != XML_ELEMENT_NODE));
7771 return(cur);
7772 }
7773 return(NULL);
7774 case XML_DOCUMENT_NODE:
7775 case XML_HTML_DOCUMENT_NODE:
7776#ifdef LIBXML_DOCB_ENABLED
7777 case XML_DOCB_DOCUMENT_NODE:
7778#endif
7779 return(xmlDocGetRootElement((xmlDocPtr) cur));
7780 default:
7781 return(NULL);
7782 }
7783 return(NULL);
7784 }
7785 /*
7786 * Get the next sibling element node.
7787 */
7788 switch (cur->type) {
7789 case XML_ELEMENT_NODE:
7790 case XML_TEXT_NODE:
7791 case XML_ENTITY_REF_NODE:
7792 case XML_ENTITY_NODE:
7793 case XML_CDATA_SECTION_NODE:
7794 case XML_PI_NODE:
7795 case XML_COMMENT_NODE:
7796 case XML_XINCLUDE_END:
7797 break;
7798 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7799 default:
7800 return(NULL);
7801 }
7802 if (cur->next != NULL) {
7803 if (cur->next->type == XML_ELEMENT_NODE)
7804 return(cur->next);
7805 cur = cur->next;
7806 do {
7807 cur = cur->next;
7808 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7809 return(cur);
7810 }
7811 return(NULL);
7812}
7813
Daniel Veillard76516062012-09-11 14:02:08 +08007814#if 0
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007815/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007816 * xmlXPathNextDescendantOrSelfElemParent:
7817 * @ctxt: the XPath Parser context
7818 * @cur: the current node in the traversal
7819 *
7820 * Traversal function for the "descendant-or-self" axis.
7821 * Additionally it returns only nodes which can be parents of
7822 * element nodes.
7823 *
7824 *
7825 * Returns the next element following that axis
7826 */
7827static xmlNodePtr
7828xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7829 xmlNodePtr contextNode)
7830{
7831 if (cur == NULL) {
7832 if (contextNode == NULL)
7833 return(NULL);
7834 switch (contextNode->type) {
7835 case XML_ELEMENT_NODE:
7836 case XML_XINCLUDE_START:
7837 case XML_DOCUMENT_FRAG_NODE:
7838 case XML_DOCUMENT_NODE:
7839#ifdef LIBXML_DOCB_ENABLED
7840 case XML_DOCB_DOCUMENT_NODE:
7841#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007842 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007843 return(contextNode);
7844 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007845 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007846 }
7847 return(NULL);
7848 } else {
7849 xmlNodePtr start = cur;
7850
7851 while (cur != NULL) {
7852 switch (cur->type) {
7853 case XML_ELEMENT_NODE:
7854 /* TODO: OK to have XInclude here? */
7855 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007856 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007857 if (cur != start)
7858 return(cur);
7859 if (cur->children != NULL) {
7860 cur = cur->children;
7861 continue;
7862 }
7863 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007864 /* Not sure if we need those here. */
7865 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007866#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007867 case XML_DOCB_DOCUMENT_NODE:
7868#endif
7869 case XML_HTML_DOCUMENT_NODE:
7870 if (cur != start)
7871 return(cur);
7872 return(xmlDocGetRootElement((xmlDocPtr) cur));
7873 default:
7874 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007875 }
7876
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007877next_sibling:
7878 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007879 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007880 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007881 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007882 } else {
7883 cur = cur->parent;
7884 goto next_sibling;
7885 }
7886 }
7887 }
7888 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007889}
Daniel Veillard76516062012-09-11 14:02:08 +08007890#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007891
7892/**
Owen Taylor3473f882001-02-23 17:55:21 +00007893 * xmlXPathNextDescendant:
7894 * @ctxt: the XPath Parser context
7895 * @cur: the current node in the traversal
7896 *
7897 * Traversal function for the "descendant" direction
7898 * the descendant axis contains the descendants of the context node in document
7899 * order; a descendant is a child or a child of a child and so on.
7900 *
7901 * Returns the next element following that axis
7902 */
7903xmlNodePtr
7904xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007905 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007906 if (cur == NULL) {
7907 if (ctxt->context->node == NULL)
7908 return(NULL);
7909 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7910 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7911 return(NULL);
7912
7913 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7914 return(ctxt->context->doc->children);
7915 return(ctxt->context->node->children);
7916 }
7917
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007918 if (cur->type == XML_NAMESPACE_DECL)
7919 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007920 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007921 /*
7922 * Do not descend on entities declarations
7923 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007924 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007925 cur = cur->children;
7926 /*
7927 * Skip DTDs
7928 */
7929 if (cur->type != XML_DTD_NODE)
7930 return(cur);
7931 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007932 }
7933
7934 if (cur == ctxt->context->node) return(NULL);
7935
Daniel Veillard68e9e742002-11-16 15:35:11 +00007936 while (cur->next != NULL) {
7937 cur = cur->next;
7938 if ((cur->type != XML_ENTITY_DECL) &&
7939 (cur->type != XML_DTD_NODE))
7940 return(cur);
7941 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007942
Owen Taylor3473f882001-02-23 17:55:21 +00007943 do {
7944 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007945 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007946 if (cur == ctxt->context->node) return(NULL);
7947 if (cur->next != NULL) {
7948 cur = cur->next;
7949 return(cur);
7950 }
7951 } while (cur != NULL);
7952 return(cur);
7953}
7954
7955/**
7956 * xmlXPathNextDescendantOrSelf:
7957 * @ctxt: the XPath Parser context
7958 * @cur: the current node in the traversal
7959 *
7960 * Traversal function for the "descendant-or-self" direction
7961 * the descendant-or-self axis contains the context node and the descendants
7962 * of the context node in document order; thus the context node is the first
7963 * node on the axis, and the first child of the context node is the second node
7964 * on the axis
7965 *
7966 * Returns the next element following that axis
7967 */
7968xmlNodePtr
7969xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007970 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007971 if (cur == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007972 return(ctxt->context->node);
Nick Wellnhoferf6aaabc2015-03-08 16:05:26 +01007973
7974 if (ctxt->context->node == NULL)
7975 return(NULL);
7976 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7977 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7978 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007979
7980 return(xmlXPathNextDescendant(ctxt, cur));
7981}
7982
7983/**
7984 * xmlXPathNextParent:
7985 * @ctxt: the XPath Parser context
7986 * @cur: the current node in the traversal
7987 *
7988 * Traversal function for the "parent" direction
7989 * The parent axis contains the parent of the context node, if there is one.
7990 *
7991 * Returns the next element following that axis
7992 */
7993xmlNodePtr
7994xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007995 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007996 /*
7997 * the parent of an attribute or namespace node is the element
7998 * to which the attribute or namespace node is attached
7999 * Namespace handling !!!
8000 */
8001 if (cur == NULL) {
8002 if (ctxt->context->node == NULL) return(NULL);
8003 switch (ctxt->context->node->type) {
8004 case XML_ELEMENT_NODE:
8005 case XML_TEXT_NODE:
8006 case XML_CDATA_SECTION_NODE:
8007 case XML_ENTITY_REF_NODE:
8008 case XML_ENTITY_NODE:
8009 case XML_PI_NODE:
8010 case XML_COMMENT_NODE:
8011 case XML_NOTATION_NODE:
8012 case XML_DTD_NODE:
8013 case XML_ELEMENT_DECL:
8014 case XML_ATTRIBUTE_DECL:
8015 case XML_XINCLUDE_START:
8016 case XML_XINCLUDE_END:
8017 case XML_ENTITY_DECL:
8018 if (ctxt->context->node->parent == NULL)
8019 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008020 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008021 ((ctxt->context->node->parent->name[0] == ' ') ||
8022 (xmlStrEqual(ctxt->context->node->parent->name,
8023 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008024 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008025 return(ctxt->context->node->parent);
8026 case XML_ATTRIBUTE_NODE: {
8027 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8028
8029 return(att->parent);
8030 }
8031 case XML_DOCUMENT_NODE:
8032 case XML_DOCUMENT_TYPE_NODE:
8033 case XML_DOCUMENT_FRAG_NODE:
8034 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008035#ifdef LIBXML_DOCB_ENABLED
8036 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008037#endif
8038 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008039 case XML_NAMESPACE_DECL: {
8040 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008041
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008042 if ((ns->next != NULL) &&
8043 (ns->next->type != XML_NAMESPACE_DECL))
8044 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00008045 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008046 }
Owen Taylor3473f882001-02-23 17:55:21 +00008047 }
8048 }
8049 return(NULL);
8050}
8051
8052/**
8053 * xmlXPathNextAncestor:
8054 * @ctxt: the XPath Parser context
8055 * @cur: the current node in the traversal
8056 *
8057 * Traversal function for the "ancestor" direction
8058 * the ancestor axis contains the ancestors of the context node; the ancestors
8059 * of the context node consist of the parent of context node and the parent's
8060 * parent and so on; the nodes are ordered in reverse document order; thus the
8061 * parent is the first node on the axis, and the parent's parent is the second
8062 * node on the axis
8063 *
8064 * Returns the next element following that axis
8065 */
8066xmlNodePtr
8067xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008068 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008069 /*
8070 * the parent of an attribute or namespace node is the element
8071 * to which the attribute or namespace node is attached
8072 * !!!!!!!!!!!!!
8073 */
8074 if (cur == NULL) {
8075 if (ctxt->context->node == NULL) return(NULL);
8076 switch (ctxt->context->node->type) {
8077 case XML_ELEMENT_NODE:
8078 case XML_TEXT_NODE:
8079 case XML_CDATA_SECTION_NODE:
8080 case XML_ENTITY_REF_NODE:
8081 case XML_ENTITY_NODE:
8082 case XML_PI_NODE:
8083 case XML_COMMENT_NODE:
8084 case XML_DTD_NODE:
8085 case XML_ELEMENT_DECL:
8086 case XML_ATTRIBUTE_DECL:
8087 case XML_ENTITY_DECL:
8088 case XML_NOTATION_NODE:
8089 case XML_XINCLUDE_START:
8090 case XML_XINCLUDE_END:
8091 if (ctxt->context->node->parent == NULL)
8092 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008093 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008094 ((ctxt->context->node->parent->name[0] == ' ') ||
8095 (xmlStrEqual(ctxt->context->node->parent->name,
8096 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008097 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008098 return(ctxt->context->node->parent);
8099 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008100 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00008101
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008102 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00008103 }
8104 case XML_DOCUMENT_NODE:
8105 case XML_DOCUMENT_TYPE_NODE:
8106 case XML_DOCUMENT_FRAG_NODE:
8107 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008108#ifdef LIBXML_DOCB_ENABLED
8109 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008110#endif
8111 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008112 case XML_NAMESPACE_DECL: {
8113 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008114
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008115 if ((ns->next != NULL) &&
8116 (ns->next->type != XML_NAMESPACE_DECL))
8117 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008118 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008119 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008120 }
Owen Taylor3473f882001-02-23 17:55:21 +00008121 }
8122 return(NULL);
8123 }
8124 if (cur == ctxt->context->doc->children)
8125 return((xmlNodePtr) ctxt->context->doc);
8126 if (cur == (xmlNodePtr) ctxt->context->doc)
8127 return(NULL);
8128 switch (cur->type) {
8129 case XML_ELEMENT_NODE:
8130 case XML_TEXT_NODE:
8131 case XML_CDATA_SECTION_NODE:
8132 case XML_ENTITY_REF_NODE:
8133 case XML_ENTITY_NODE:
8134 case XML_PI_NODE:
8135 case XML_COMMENT_NODE:
8136 case XML_NOTATION_NODE:
8137 case XML_DTD_NODE:
8138 case XML_ELEMENT_DECL:
8139 case XML_ATTRIBUTE_DECL:
8140 case XML_ENTITY_DECL:
8141 case XML_XINCLUDE_START:
8142 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008143 if (cur->parent == NULL)
8144 return(NULL);
8145 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008146 ((cur->parent->name[0] == ' ') ||
8147 (xmlStrEqual(cur->parent->name,
8148 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008149 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008150 return(cur->parent);
8151 case XML_ATTRIBUTE_NODE: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008152 xmlAttrPtr att = (xmlAttrPtr) cur;
Owen Taylor3473f882001-02-23 17:55:21 +00008153
8154 return(att->parent);
8155 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008156 case XML_NAMESPACE_DECL: {
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008157 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008158
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008159 if ((ns->next != NULL) &&
8160 (ns->next->type != XML_NAMESPACE_DECL))
8161 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008162 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008163 return(NULL);
8164 }
Owen Taylor3473f882001-02-23 17:55:21 +00008165 case XML_DOCUMENT_NODE:
8166 case XML_DOCUMENT_TYPE_NODE:
8167 case XML_DOCUMENT_FRAG_NODE:
8168 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008169#ifdef LIBXML_DOCB_ENABLED
8170 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008171#endif
8172 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008173 }
8174 return(NULL);
8175}
8176
8177/**
8178 * xmlXPathNextAncestorOrSelf:
8179 * @ctxt: the XPath Parser context
8180 * @cur: the current node in the traversal
8181 *
8182 * Traversal function for the "ancestor-or-self" direction
8183 * he ancestor-or-self axis contains the context node and ancestors of
8184 * the context node in reverse document order; thus the context node is
8185 * the first node on the axis, and the context node's parent the second;
8186 * parent here is defined the same as with the parent axis.
8187 *
8188 * Returns the next element following that axis
8189 */
8190xmlNodePtr
8191xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008192 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008193 if (cur == NULL)
8194 return(ctxt->context->node);
8195 return(xmlXPathNextAncestor(ctxt, cur));
8196}
8197
8198/**
8199 * xmlXPathNextFollowingSibling:
8200 * @ctxt: the XPath Parser context
8201 * @cur: the current node in the traversal
8202 *
8203 * Traversal function for the "following-sibling" direction
8204 * The following-sibling axis contains the following siblings of the context
8205 * node in document order.
8206 *
8207 * Returns the next element following that axis
8208 */
8209xmlNodePtr
8210xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008211 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008212 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8213 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8214 return(NULL);
8215 if (cur == (xmlNodePtr) ctxt->context->doc)
8216 return(NULL);
8217 if (cur == NULL)
8218 return(ctxt->context->node->next);
8219 return(cur->next);
8220}
8221
8222/**
8223 * xmlXPathNextPrecedingSibling:
8224 * @ctxt: the XPath Parser context
8225 * @cur: the current node in the traversal
8226 *
8227 * Traversal function for the "preceding-sibling" direction
8228 * The preceding-sibling axis contains the preceding siblings of the context
8229 * node in reverse document order; the first preceding sibling is first on the
8230 * axis; the sibling preceding that node is the second on the axis and so on.
8231 *
8232 * Returns the next element following that axis
8233 */
8234xmlNodePtr
8235xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008236 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008237 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8238 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8239 return(NULL);
8240 if (cur == (xmlNodePtr) ctxt->context->doc)
8241 return(NULL);
8242 if (cur == NULL)
8243 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008244 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8245 cur = cur->prev;
8246 if (cur == NULL)
8247 return(ctxt->context->node->prev);
8248 }
Owen Taylor3473f882001-02-23 17:55:21 +00008249 return(cur->prev);
8250}
8251
8252/**
8253 * xmlXPathNextFollowing:
8254 * @ctxt: the XPath Parser context
8255 * @cur: the current node in the traversal
8256 *
8257 * Traversal function for the "following" direction
8258 * The following axis contains all nodes in the same document as the context
8259 * node that are after the context node in document order, excluding any
8260 * descendants and excluding attribute nodes and namespace nodes; the nodes
8261 * are ordered in document order
8262 *
8263 * Returns the next element following that axis
8264 */
8265xmlNodePtr
8266xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008267 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008268 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8269 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8270 return(cur->children);
8271
8272 if (cur == NULL) {
8273 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008274 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardea90b892010-10-22 15:50:50 +02008275 cur = cur->parent;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008276 } else if (cur->type == XML_NAMESPACE_DECL) {
8277 xmlNsPtr ns = (xmlNsPtr) cur;
8278
8279 if ((ns->next == NULL) ||
8280 (ns->next->type == XML_NAMESPACE_DECL))
8281 return (NULL);
8282 cur = (xmlNodePtr) ns->next;
8283 }
Daniel Veillard91d19752010-10-15 14:30:52 +02008284 }
Owen Taylor3473f882001-02-23 17:55:21 +00008285 if (cur == NULL) return(NULL) ; /* ERROR */
8286 if (cur->next != NULL) return(cur->next) ;
8287 do {
8288 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008289 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008290 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8291 if (cur->next != NULL) return(cur->next);
8292 } while (cur != NULL);
8293 return(cur);
8294}
8295
8296/*
8297 * xmlXPathIsAncestor:
8298 * @ancestor: the ancestor node
8299 * @node: the current node
8300 *
8301 * Check that @ancestor is a @node's ancestor
8302 *
8303 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8304 */
8305static int
8306xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8307 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008308 if (node->type == XML_NAMESPACE_DECL)
8309 return(0);
8310 if (ancestor->type == XML_NAMESPACE_DECL)
8311 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008312 /* nodes need to be in the same document */
8313 if (ancestor->doc != node->doc) return(0);
8314 /* avoid searching if ancestor or node is the root node */
8315 if (ancestor == (xmlNodePtr) node->doc) return(1);
8316 if (node == (xmlNodePtr) ancestor->doc) return(0);
8317 while (node->parent != NULL) {
8318 if (node->parent == ancestor)
8319 return(1);
8320 node = node->parent;
8321 }
8322 return(0);
8323}
8324
8325/**
8326 * xmlXPathNextPreceding:
8327 * @ctxt: the XPath Parser context
8328 * @cur: the current node in the traversal
8329 *
8330 * Traversal function for the "preceding" direction
8331 * the preceding axis contains all nodes in the same document as the context
8332 * node that are before the context node in document order, excluding any
8333 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8334 * ordered in reverse document order
8335 *
8336 * Returns the next element following that axis
8337 */
8338xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008339xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8340{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008341 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008342 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008343 cur = ctxt->context->node;
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008344 if (cur->type == XML_ATTRIBUTE_NODE) {
8345 cur = cur->parent;
8346 } else if (cur->type == XML_NAMESPACE_DECL) {
8347 xmlNsPtr ns = (xmlNsPtr) cur;
8348
8349 if ((ns->next == NULL) ||
8350 (ns->next->type == XML_NAMESPACE_DECL))
8351 return (NULL);
8352 cur = (xmlNodePtr) ns->next;
8353 }
Daniel Veillardea90b892010-10-22 15:50:50 +02008354 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008355 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008356 return (NULL);
8357 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8358 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008359 do {
8360 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008361 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8362 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008363 }
8364
8365 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008366 if (cur == NULL)
8367 return (NULL);
8368 if (cur == ctxt->context->doc->children)
8369 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008370 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008371 return (cur);
8372}
8373
8374/**
8375 * xmlXPathNextPrecedingInternal:
8376 * @ctxt: the XPath Parser context
8377 * @cur: the current node in the traversal
8378 *
8379 * Traversal function for the "preceding" direction
8380 * the preceding axis contains all nodes in the same document as the context
8381 * node that are before the context node in document order, excluding any
8382 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8383 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008384 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008385 * state kept in the parser context: ctxt->ancestor.
8386 *
8387 * Returns the next element following that axis
8388 */
8389static xmlNodePtr
8390xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8391 xmlNodePtr cur)
8392{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008393 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008394 if (cur == NULL) {
8395 cur = ctxt->context->node;
8396 if (cur == NULL)
8397 return (NULL);
Nick Wellnhofer40f58522017-05-26 20:16:35 +02008398 if (cur->type == XML_ATTRIBUTE_NODE) {
8399 cur = cur->parent;
8400 } else if (cur->type == XML_NAMESPACE_DECL) {
8401 xmlNsPtr ns = (xmlNsPtr) cur;
8402
8403 if ((ns->next == NULL) ||
8404 (ns->next->type == XML_NAMESPACE_DECL))
8405 return (NULL);
8406 cur = (xmlNodePtr) ns->next;
8407 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00008408 ctxt->ancestor = cur->parent;
8409 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008410 if (cur->type == XML_NAMESPACE_DECL)
8411 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008412 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8413 cur = cur->prev;
8414 while (cur->prev == NULL) {
8415 cur = cur->parent;
8416 if (cur == NULL)
8417 return (NULL);
8418 if (cur == ctxt->context->doc->children)
8419 return (NULL);
8420 if (cur != ctxt->ancestor)
8421 return (cur);
8422 ctxt->ancestor = cur->parent;
8423 }
8424 cur = cur->prev;
8425 while (cur->last != NULL)
8426 cur = cur->last;
8427 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008428}
8429
8430/**
8431 * xmlXPathNextNamespace:
8432 * @ctxt: the XPath Parser context
8433 * @cur: the current attribute in the traversal
8434 *
8435 * Traversal function for the "namespace" direction
8436 * the namespace axis contains the namespace nodes of the context node;
8437 * the order of nodes on this axis is implementation-defined; the axis will
8438 * be empty unless the context node is an element
8439 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008440 * We keep the XML namespace node at the end of the list.
8441 *
Owen Taylor3473f882001-02-23 17:55:21 +00008442 * Returns the next element following that axis
8443 */
8444xmlNodePtr
8445xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008446 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008447 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Nick Wellnhofer82b73032016-04-30 17:53:10 +02008448 if (cur == NULL) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008449 if (ctxt->context->tmpNsList != NULL)
8450 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008451 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008452 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008453 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008454 if (ctxt->context->tmpNsList != NULL) {
8455 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8456 ctxt->context->tmpNsNr++;
8457 }
8458 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008459 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008460 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008461 if (ctxt->context->tmpNsNr > 0) {
8462 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8463 } else {
8464 if (ctxt->context->tmpNsList != NULL)
8465 xmlFree(ctxt->context->tmpNsList);
8466 ctxt->context->tmpNsList = NULL;
8467 return(NULL);
8468 }
Owen Taylor3473f882001-02-23 17:55:21 +00008469}
8470
8471/**
8472 * xmlXPathNextAttribute:
8473 * @ctxt: the XPath Parser context
8474 * @cur: the current attribute in the traversal
8475 *
8476 * Traversal function for the "attribute" direction
8477 * TODO: support DTD inherited default attributes
8478 *
8479 * Returns the next element following that axis
8480 */
8481xmlNodePtr
8482xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008483 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008484 if (ctxt->context->node == NULL)
8485 return(NULL);
8486 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8487 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008488 if (cur == NULL) {
8489 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8490 return(NULL);
8491 return((xmlNodePtr)ctxt->context->node->properties);
8492 }
8493 return((xmlNodePtr)cur->next);
8494}
8495
8496/************************************************************************
8497 * *
8498 * NodeTest Functions *
8499 * *
8500 ************************************************************************/
8501
Owen Taylor3473f882001-02-23 17:55:21 +00008502#define IS_FUNCTION 200
8503
Owen Taylor3473f882001-02-23 17:55:21 +00008504
8505/************************************************************************
8506 * *
8507 * Implicit tree core function library *
8508 * *
8509 ************************************************************************/
8510
8511/**
8512 * xmlXPathRoot:
8513 * @ctxt: the XPath Parser context
8514 *
8515 * Initialize the context to the root of the document
8516 */
8517void
8518xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008519 if ((ctxt == NULL) || (ctxt->context == NULL))
8520 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008521 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008522 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8523 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008524}
8525
8526/************************************************************************
8527 * *
8528 * The explicit core function library *
8529 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8530 * *
8531 ************************************************************************/
8532
8533
8534/**
8535 * xmlXPathLastFunction:
8536 * @ctxt: the XPath Parser context
8537 * @nargs: the number of arguments
8538 *
8539 * Implement the last() XPath function
8540 * number last()
8541 * The last function returns the number of nodes in the context node list.
8542 */
8543void
8544xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8545 CHECK_ARITY(0);
8546 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008547 valuePush(ctxt,
8548 xmlXPathCacheNewFloat(ctxt->context,
8549 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008550#ifdef DEBUG_EXPR
8551 xmlGenericError(xmlGenericErrorContext,
8552 "last() : %d\n", ctxt->context->contextSize);
8553#endif
8554 } else {
8555 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8556 }
8557}
8558
8559/**
8560 * xmlXPathPositionFunction:
8561 * @ctxt: the XPath Parser context
8562 * @nargs: the number of arguments
8563 *
8564 * Implement the position() XPath function
8565 * number position()
8566 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008567 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008568 * will be equal to last().
8569 */
8570void
8571xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8572 CHECK_ARITY(0);
8573 if (ctxt->context->proximityPosition >= 0) {
8574 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008575 xmlXPathCacheNewFloat(ctxt->context,
8576 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008577#ifdef DEBUG_EXPR
8578 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8579 ctxt->context->proximityPosition);
8580#endif
8581 } else {
8582 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8583 }
8584}
8585
8586/**
8587 * xmlXPathCountFunction:
8588 * @ctxt: the XPath Parser context
8589 * @nargs: the number of arguments
8590 *
8591 * Implement the count() XPath function
8592 * number count(node-set)
8593 */
8594void
8595xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8596 xmlXPathObjectPtr cur;
8597
8598 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008599 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008600 ((ctxt->value->type != XPATH_NODESET) &&
8601 (ctxt->value->type != XPATH_XSLT_TREE)))
8602 XP_ERROR(XPATH_INVALID_TYPE);
8603 cur = valuePop(ctxt);
8604
Daniel Veillard911f49a2001-04-07 15:39:35 +00008605 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008606 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008607 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008608 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8609 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008610 } else {
8611 if ((cur->nodesetval->nodeNr != 1) ||
8612 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008613 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008614 } else {
8615 xmlNodePtr tmp;
8616 int i = 0;
8617
8618 tmp = cur->nodesetval->nodeTab[0];
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008619 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
Daniel Veillardfe703322001-08-14 12:18:09 +00008620 tmp = tmp->children;
8621 while (tmp != NULL) {
8622 tmp = tmp->next;
8623 i++;
8624 }
8625 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008626 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008627 }
8628 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008629 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008630}
8631
8632/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008633 * xmlXPathGetElementsByIds:
8634 * @doc: the document
8635 * @ids: a whitespace separated list of IDs
8636 *
8637 * Selects elements by their unique ID.
8638 *
8639 * Returns a node-set of selected elements.
8640 */
8641static xmlNodeSetPtr
8642xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8643 xmlNodeSetPtr ret;
8644 const xmlChar *cur = ids;
8645 xmlChar *ID;
8646 xmlAttrPtr attr;
8647 xmlNodePtr elem = NULL;
8648
Daniel Veillard7a985a12003-07-06 17:57:42 +00008649 if (ids == NULL) return(NULL);
8650
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008651 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008652 if (ret == NULL)
8653 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008654
William M. Brack76e95df2003-10-18 16:20:14 +00008655 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008656 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008657 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008658 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008659
8660 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008661 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008662 /*
8663 * We used to check the fact that the value passed
8664 * was an NCName, but this generated much troubles for
8665 * me and Aleksey Sanin, people blatantly violated that
8666 * constaint, like Visa3D spec.
8667 * if (xmlValidateNCName(ID, 1) == 0)
8668 */
8669 attr = xmlGetID(doc, ID);
8670 if (attr != NULL) {
8671 if (attr->type == XML_ATTRIBUTE_NODE)
8672 elem = attr->parent;
8673 else if (attr->type == XML_ELEMENT_NODE)
8674 elem = (xmlNodePtr) attr;
8675 else
8676 elem = NULL;
8677 if (elem != NULL)
8678 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008679 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008680 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008681 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008682
William M. Brack76e95df2003-10-18 16:20:14 +00008683 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008684 ids = cur;
8685 }
8686 return(ret);
8687}
8688
8689/**
Owen Taylor3473f882001-02-23 17:55:21 +00008690 * xmlXPathIdFunction:
8691 * @ctxt: the XPath Parser context
8692 * @nargs: the number of arguments
8693 *
8694 * Implement the id() XPath function
8695 * node-set id(object)
8696 * The id function selects elements by their unique ID
8697 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8698 * then the result is the union of the result of applying id to the
8699 * string value of each of the nodes in the argument node-set. When the
8700 * argument to id is of any other type, the argument is converted to a
8701 * string as if by a call to the string function; the string is split
8702 * into a whitespace-separated list of tokens (whitespace is any sequence
8703 * of characters matching the production S); the result is a node-set
8704 * containing the elements in the same document as the context node that
8705 * have a unique ID equal to any of the tokens in the list.
8706 */
8707void
8708xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008709 xmlChar *tokens;
8710 xmlNodeSetPtr ret;
8711 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008712
8713 CHECK_ARITY(1);
8714 obj = valuePop(ctxt);
8715 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008716 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008717 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008718 int i;
8719
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008720 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008721 /*
8722 * FIXME -- in an out-of-memory condition this will behave badly.
8723 * The solution is not clear -- we already popped an item from
8724 * ctxt, so the object is in a corrupt state.
8725 */
Owen Taylor3473f882001-02-23 17:55:21 +00008726
Daniel Veillard911f49a2001-04-07 15:39:35 +00008727 if (obj->nodesetval != NULL) {
8728 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008729 tokens =
8730 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8731 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8732 ret = xmlXPathNodeSetMerge(ret, ns);
8733 xmlXPathFreeNodeSet(ns);
8734 if (tokens != NULL)
8735 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008736 }
Owen Taylor3473f882001-02-23 17:55:21 +00008737 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008738 xmlXPathReleaseObject(ctxt->context, obj);
8739 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008740 return;
8741 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008742 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008743 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008744 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008745 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008746 return;
8747}
8748
8749/**
8750 * xmlXPathLocalNameFunction:
8751 * @ctxt: the XPath Parser context
8752 * @nargs: the number of arguments
8753 *
8754 * Implement the local-name() XPath function
8755 * string local-name(node-set?)
8756 * The local-name function returns a string containing the local part
8757 * of the name of the node in the argument node-set that is first in
8758 * document order. If the node-set is empty or the first node has no
8759 * name, an empty string is returned. If the argument is omitted it
8760 * defaults to the context node.
8761 */
8762void
8763xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8764 xmlXPathObjectPtr cur;
8765
Daniel Veillarda82b1822004-11-08 16:24:57 +00008766 if (ctxt == NULL) return;
8767
Owen Taylor3473f882001-02-23 17:55:21 +00008768 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008769 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8770 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008771 nargs = 1;
8772 }
8773
8774 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008775 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008776 ((ctxt->value->type != XPATH_NODESET) &&
8777 (ctxt->value->type != XPATH_XSLT_TREE)))
8778 XP_ERROR(XPATH_INVALID_TYPE);
8779 cur = valuePop(ctxt);
8780
Daniel Veillard911f49a2001-04-07 15:39:35 +00008781 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008782 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008783 } else {
8784 int i = 0; /* Should be first in document order !!!!! */
8785 switch (cur->nodesetval->nodeTab[i]->type) {
8786 case XML_ELEMENT_NODE:
8787 case XML_ATTRIBUTE_NODE:
8788 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008789 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008790 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008791 else
8792 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008793 xmlXPathCacheNewString(ctxt->context,
8794 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008795 break;
8796 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008797 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008798 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8799 break;
8800 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008801 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008802 }
8803 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008804 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008805}
8806
8807/**
8808 * xmlXPathNamespaceURIFunction:
8809 * @ctxt: the XPath Parser context
8810 * @nargs: the number of arguments
8811 *
8812 * Implement the namespace-uri() XPath function
8813 * string namespace-uri(node-set?)
8814 * The namespace-uri function returns a string containing the
8815 * namespace URI of the expanded name of the node in the argument
8816 * node-set that is first in document order. If the node-set is empty,
8817 * the first node has no name, or the expanded name has no namespace
8818 * URI, an empty string is returned. If the argument is omitted it
8819 * defaults to the context node.
8820 */
8821void
8822xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8823 xmlXPathObjectPtr cur;
8824
Daniel Veillarda82b1822004-11-08 16:24:57 +00008825 if (ctxt == NULL) return;
8826
Owen Taylor3473f882001-02-23 17:55:21 +00008827 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008828 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8829 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008830 nargs = 1;
8831 }
8832 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008833 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008834 ((ctxt->value->type != XPATH_NODESET) &&
8835 (ctxt->value->type != XPATH_XSLT_TREE)))
8836 XP_ERROR(XPATH_INVALID_TYPE);
8837 cur = valuePop(ctxt);
8838
Daniel Veillard911f49a2001-04-07 15:39:35 +00008839 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008840 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008841 } else {
8842 int i = 0; /* Should be first in document order !!!!! */
8843 switch (cur->nodesetval->nodeTab[i]->type) {
8844 case XML_ELEMENT_NODE:
8845 case XML_ATTRIBUTE_NODE:
8846 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008847 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008848 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008849 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008850 cur->nodesetval->nodeTab[i]->ns->href));
8851 break;
8852 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008853 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008854 }
8855 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008856 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008857}
8858
8859/**
8860 * xmlXPathNameFunction:
8861 * @ctxt: the XPath Parser context
8862 * @nargs: the number of arguments
8863 *
8864 * Implement the name() XPath function
8865 * string name(node-set?)
8866 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008867 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008868 * order. The QName must represent the name with respect to the namespace
8869 * declarations in effect on the node whose name is being represented.
8870 * Typically, this will be the form in which the name occurred in the XML
8871 * source. This need not be the case if there are namespace declarations
8872 * in effect on the node that associate multiple prefixes with the same
8873 * namespace. However, an implementation may include information about
8874 * the original prefix in its representation of nodes; in this case, an
8875 * implementation can ensure that the returned string is always the same
8876 * as the QName used in the XML source. If the argument it omitted it
8877 * defaults to the context node.
8878 * Libxml keep the original prefix so the "real qualified name" used is
8879 * returned.
8880 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008881static void
Daniel Veillard04383752001-07-08 14:27:15 +00008882xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8883{
Owen Taylor3473f882001-02-23 17:55:21 +00008884 xmlXPathObjectPtr cur;
8885
8886 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008887 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8888 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008889 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008890 }
8891
8892 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008893 if ((ctxt->value == NULL) ||
8894 ((ctxt->value->type != XPATH_NODESET) &&
8895 (ctxt->value->type != XPATH_XSLT_TREE)))
8896 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008897 cur = valuePop(ctxt);
8898
Daniel Veillard911f49a2001-04-07 15:39:35 +00008899 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008900 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008901 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008902 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008903
Daniel Veillard04383752001-07-08 14:27:15 +00008904 switch (cur->nodesetval->nodeTab[i]->type) {
8905 case XML_ELEMENT_NODE:
8906 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008907 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008908 valuePush(ctxt,
8909 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008910 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8911 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008912 valuePush(ctxt,
8913 xmlXPathCacheNewString(ctxt->context,
8914 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008915 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008916 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008917
Daniel Veillardc00cda82003-04-07 10:22:39 +00008918 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8919 cur->nodesetval->nodeTab[i]->ns->prefix,
8920 NULL, 0);
8921 if (fullname == cur->nodesetval->nodeTab[i]->name)
8922 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8923 if (fullname == NULL) {
8924 XP_ERROR(XPATH_MEMORY_ERROR);
8925 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008926 valuePush(ctxt, xmlXPathCacheWrapString(
8927 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008928 }
8929 break;
8930 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008931 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8932 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008933 xmlXPathLocalNameFunction(ctxt, 1);
8934 }
Owen Taylor3473f882001-02-23 17:55:21 +00008935 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008936 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008937}
8938
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008939
8940/**
Owen Taylor3473f882001-02-23 17:55:21 +00008941 * xmlXPathStringFunction:
8942 * @ctxt: the XPath Parser context
8943 * @nargs: the number of arguments
8944 *
8945 * Implement the string() XPath function
8946 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008947 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008948 * - A node-set is converted to a string by returning the value of
8949 * the node in the node-set that is first in document order.
8950 * If the node-set is empty, an empty string is returned.
8951 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008952 * + NaN is converted to the string NaN
8953 * + positive zero is converted to the string 0
8954 * + negative zero is converted to the string 0
8955 * + positive infinity is converted to the string Infinity
8956 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008957 * + if the number is an integer, the number is represented in
8958 * decimal form as a Number with no decimal point and no leading
8959 * zeros, preceded by a minus sign (-) if the number is negative
8960 * + otherwise, the number is represented in decimal form as a
8961 * Number including a decimal point with at least one digit
8962 * before the decimal point and at least one digit after the
8963 * decimal point, preceded by a minus sign (-) if the number
8964 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008965 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008966 * before the decimal point; beyond the one required digit
8967 * after the decimal point there must be as many, but only as
8968 * many, more digits as are needed to uniquely distinguish the
8969 * number from all other IEEE 754 numeric values.
8970 * - The boolean false value is converted to the string false.
8971 * The boolean true value is converted to the string true.
8972 *
8973 * If the argument is omitted, it defaults to a node-set with the
8974 * context node as its only member.
8975 */
8976void
8977xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8978 xmlXPathObjectPtr cur;
8979
Daniel Veillarda82b1822004-11-08 16:24:57 +00008980 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008981 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008982 valuePush(ctxt,
8983 xmlXPathCacheWrapString(ctxt->context,
8984 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008985 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008986 }
8987
8988 CHECK_ARITY(1);
8989 cur = valuePop(ctxt);
8990 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008991 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008992}
8993
8994/**
8995 * xmlXPathStringLengthFunction:
8996 * @ctxt: the XPath Parser context
8997 * @nargs: the number of arguments
8998 *
8999 * Implement the string-length() XPath function
9000 * number string-length(string?)
9001 * The string-length returns the number of characters in the string
9002 * (see [3.6 Strings]). If the argument is omitted, it defaults to
9003 * the context node converted to a string, in other words the value
9004 * of the context node.
9005 */
9006void
9007xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9008 xmlXPathObjectPtr cur;
9009
9010 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00009011 if ((ctxt == NULL) || (ctxt->context == NULL))
9012 return;
Owen Taylor3473f882001-02-23 17:55:21 +00009013 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009014 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009015 } else {
9016 xmlChar *content;
9017
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009018 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009019 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9020 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00009021 xmlFree(content);
9022 }
9023 return;
9024 }
9025 CHECK_ARITY(1);
9026 CAST_TO_STRING;
9027 CHECK_TYPE(XPATH_STRING);
9028 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009029 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00009030 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009031 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009032}
9033
9034/**
9035 * xmlXPathConcatFunction:
9036 * @ctxt: the XPath Parser context
9037 * @nargs: the number of arguments
9038 *
9039 * Implement the concat() XPath function
9040 * string concat(string, string, string*)
9041 * The concat function returns the concatenation of its arguments.
9042 */
9043void
9044xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9045 xmlXPathObjectPtr cur, newobj;
9046 xmlChar *tmp;
9047
Daniel Veillarda82b1822004-11-08 16:24:57 +00009048 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009049 if (nargs < 2) {
9050 CHECK_ARITY(2);
9051 }
9052
9053 CAST_TO_STRING;
9054 cur = valuePop(ctxt);
9055 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009056 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009057 return;
9058 }
9059 nargs--;
9060
9061 while (nargs > 0) {
9062 CAST_TO_STRING;
9063 newobj = valuePop(ctxt);
9064 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009065 xmlXPathReleaseObject(ctxt->context, newobj);
9066 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009067 XP_ERROR(XPATH_INVALID_TYPE);
9068 }
9069 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9070 newobj->stringval = cur->stringval;
9071 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009072 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00009073 nargs--;
9074 }
9075 valuePush(ctxt, cur);
9076}
9077
9078/**
9079 * xmlXPathContainsFunction:
9080 * @ctxt: the XPath Parser context
9081 * @nargs: the number of arguments
9082 *
9083 * Implement the contains() XPath function
9084 * boolean contains(string, string)
9085 * The contains function returns true if the first argument string
9086 * contains the second argument string, and otherwise returns false.
9087 */
9088void
9089xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9090 xmlXPathObjectPtr hay, needle;
9091
9092 CHECK_ARITY(2);
9093 CAST_TO_STRING;
9094 CHECK_TYPE(XPATH_STRING);
9095 needle = valuePop(ctxt);
9096 CAST_TO_STRING;
9097 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009098
Owen Taylor3473f882001-02-23 17:55:21 +00009099 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009100 xmlXPathReleaseObject(ctxt->context, hay);
9101 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009102 XP_ERROR(XPATH_INVALID_TYPE);
9103 }
9104 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009105 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009106 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009107 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9108 xmlXPathReleaseObject(ctxt->context, hay);
9109 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009110}
9111
9112/**
9113 * xmlXPathStartsWithFunction:
9114 * @ctxt: the XPath Parser context
9115 * @nargs: the number of arguments
9116 *
9117 * Implement the starts-with() XPath function
9118 * boolean starts-with(string, string)
9119 * The starts-with function returns true if the first argument string
9120 * starts with the second argument string, and otherwise returns false.
9121 */
9122void
9123xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9124 xmlXPathObjectPtr hay, needle;
9125 int n;
9126
9127 CHECK_ARITY(2);
9128 CAST_TO_STRING;
9129 CHECK_TYPE(XPATH_STRING);
9130 needle = valuePop(ctxt);
9131 CAST_TO_STRING;
9132 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009133
Owen Taylor3473f882001-02-23 17:55:21 +00009134 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009135 xmlXPathReleaseObject(ctxt->context, hay);
9136 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009137 XP_ERROR(XPATH_INVALID_TYPE);
9138 }
9139 n = xmlStrlen(needle->stringval);
9140 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009141 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009142 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009143 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9144 xmlXPathReleaseObject(ctxt->context, hay);
9145 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009146}
9147
9148/**
9149 * xmlXPathSubstringFunction:
9150 * @ctxt: the XPath Parser context
9151 * @nargs: the number of arguments
9152 *
9153 * Implement the substring() XPath function
9154 * string substring(string, number, number?)
9155 * The substring function returns the substring of the first argument
9156 * starting at the position specified in the second argument with
9157 * length specified in the third argument. For example,
9158 * substring("12345",2,3) returns "234". If the third argument is not
9159 * specified, it returns the substring starting at the position specified
9160 * in the second argument and continuing to the end of the string. For
9161 * example, substring("12345",2) returns "2345". More precisely, each
9162 * character in the string (see [3.6 Strings]) is considered to have a
9163 * numeric position: the position of the first character is 1, the position
9164 * of the second character is 2 and so on. The returned substring contains
9165 * those characters for which the position of the character is greater than
9166 * or equal to the second argument and, if the third argument is specified,
9167 * less than the sum of the second and third arguments; the comparisons
9168 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009169 * - substring("12345", 1.5, 2.6) returns "234"
9170 * - substring("12345", 0, 3) returns "12"
9171 * - substring("12345", 0 div 0, 3) returns ""
9172 * - substring("12345", 1, 0 div 0) returns ""
9173 * - substring("12345", -42, 1 div 0) returns "12345"
9174 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009175 */
9176void
9177xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9178 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009179 double le=0, in;
9180 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009181 xmlChar *ret;
9182
Owen Taylor3473f882001-02-23 17:55:21 +00009183 if (nargs < 2) {
9184 CHECK_ARITY(2);
9185 }
9186 if (nargs > 3) {
9187 CHECK_ARITY(3);
9188 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009189 /*
9190 * take care of possible last (position) argument
9191 */
Owen Taylor3473f882001-02-23 17:55:21 +00009192 if (nargs == 3) {
9193 CAST_TO_NUMBER;
9194 CHECK_TYPE(XPATH_NUMBER);
9195 len = valuePop(ctxt);
9196 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009197 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009198 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009199
Owen Taylor3473f882001-02-23 17:55:21 +00009200 CAST_TO_NUMBER;
9201 CHECK_TYPE(XPATH_NUMBER);
9202 start = valuePop(ctxt);
9203 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009204 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009205 CAST_TO_STRING;
9206 CHECK_TYPE(XPATH_STRING);
9207 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009208 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009209
Daniel Veillard97ac1312001-05-30 19:14:17 +00009210 /*
9211 * If last pos not present, calculate last position
9212 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009213 if (nargs != 3) {
9214 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009215 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009216 in = 1.0;
9217 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009218
Daniel Veillard45490ae2008-07-29 09:13:19 +00009219 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009220 * the index is NaN, the length is NaN, or both
9221 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009222 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009223 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009224 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009225 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009226 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009227 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009228 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009229 * First we go to integer form, rounding up
9230 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009231 */
9232 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009233 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009234
Daniel Veillard9e412302002-06-10 15:59:44 +00009235 if (xmlXPathIsInf(le) == 1) {
9236 l = m;
9237 if (i < 1)
9238 i = 1;
9239 }
9240 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9241 l = 0;
9242 else {
9243 l = (int) le;
9244 if (((double)l)+0.5 <= le) l++;
9245 }
9246
9247 /* Now we normalize inidices */
9248 i -= 1;
9249 l += i;
9250 if (i < 0)
9251 i = 0;
9252 if (l > m)
9253 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009254
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009255 /* number of chars to copy */
9256 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009257
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009258 ret = xmlUTF8Strsub(str->stringval, i, l);
9259 }
9260 else {
9261 ret = NULL;
9262 }
Owen Taylor3473f882001-02-23 17:55:21 +00009263 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009264 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009265 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009266 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009267 xmlFree(ret);
9268 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009269 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009270}
9271
9272/**
9273 * xmlXPathSubstringBeforeFunction:
9274 * @ctxt: the XPath Parser context
9275 * @nargs: the number of arguments
9276 *
9277 * Implement the substring-before() XPath function
9278 * string substring-before(string, string)
9279 * The substring-before function returns the substring of the first
9280 * argument string that precedes the first occurrence of the second
9281 * argument string in the first argument string, or the empty string
9282 * if the first argument string does not contain the second argument
9283 * string. For example, substring-before("1999/04/01","/") returns 1999.
9284 */
9285void
9286xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9287 xmlXPathObjectPtr str;
9288 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009289 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009290 const xmlChar *point;
9291 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009292
Owen Taylor3473f882001-02-23 17:55:21 +00009293 CHECK_ARITY(2);
9294 CAST_TO_STRING;
9295 find = valuePop(ctxt);
9296 CAST_TO_STRING;
9297 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009298
Daniel Veillardade10f22012-07-12 09:43:27 +08009299 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009300 if (target) {
9301 point = xmlStrstr(str->stringval, find->stringval);
9302 if (point) {
9303 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009304 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009305 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009306 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009307 xmlBufContent(target)));
9308 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009309 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009310 xmlXPathReleaseObject(ctxt->context, str);
9311 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009312}
9313
9314/**
9315 * xmlXPathSubstringAfterFunction:
9316 * @ctxt: the XPath Parser context
9317 * @nargs: the number of arguments
9318 *
9319 * Implement the substring-after() XPath function
9320 * string substring-after(string, string)
9321 * The substring-after function returns the substring of the first
9322 * argument string that follows the first occurrence of the second
9323 * argument string in the first argument string, or the empty stringi
9324 * if the first argument string does not contain the second argument
9325 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9326 * and substring-after("1999/04/01","19") returns 99/04/01.
9327 */
9328void
9329xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9330 xmlXPathObjectPtr str;
9331 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009332 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009333 const xmlChar *point;
9334 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009335
Owen Taylor3473f882001-02-23 17:55:21 +00009336 CHECK_ARITY(2);
9337 CAST_TO_STRING;
9338 find = valuePop(ctxt);
9339 CAST_TO_STRING;
9340 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009341
Daniel Veillardade10f22012-07-12 09:43:27 +08009342 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009343 if (target) {
9344 point = xmlStrstr(str->stringval, find->stringval);
9345 if (point) {
9346 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009347 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009348 xmlStrlen(str->stringval) - offset);
9349 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009350 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009351 xmlBufContent(target)));
9352 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009353 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009354 xmlXPathReleaseObject(ctxt->context, str);
9355 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009356}
9357
9358/**
9359 * xmlXPathNormalizeFunction:
9360 * @ctxt: the XPath Parser context
9361 * @nargs: the number of arguments
9362 *
9363 * Implement the normalize-space() XPath function
9364 * string normalize-space(string?)
9365 * The normalize-space function returns the argument string with white
9366 * space normalized by stripping leading and trailing whitespace
9367 * and replacing sequences of whitespace characters by a single
9368 * space. Whitespace characters are the same allowed by the S production
9369 * in XML. If the argument is omitted, it defaults to the context
9370 * node converted to a string, in other words the value of the context node.
9371 */
9372void
9373xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9374 xmlXPathObjectPtr obj = NULL;
9375 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009376 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009377 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009378
Daniel Veillarda82b1822004-11-08 16:24:57 +00009379 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009380 if (nargs == 0) {
9381 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009382 valuePush(ctxt,
9383 xmlXPathCacheWrapString(ctxt->context,
9384 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009385 nargs = 1;
9386 }
9387
9388 CHECK_ARITY(1);
9389 CAST_TO_STRING;
9390 CHECK_TYPE(XPATH_STRING);
9391 obj = valuePop(ctxt);
9392 source = obj->stringval;
9393
Daniel Veillardade10f22012-07-12 09:43:27 +08009394 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009395 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009396
Owen Taylor3473f882001-02-23 17:55:21 +00009397 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009398 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009399 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009400
Owen Taylor3473f882001-02-23 17:55:21 +00009401 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9402 blank = 0;
9403 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009404 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009405 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009406 } else {
9407 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009408 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009409 blank = 0;
9410 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009411 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009412 }
9413 source++;
9414 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009415 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009416 xmlBufContent(target)));
9417 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009418 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009419 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009420}
9421
9422/**
9423 * xmlXPathTranslateFunction:
9424 * @ctxt: the XPath Parser context
9425 * @nargs: the number of arguments
9426 *
9427 * Implement the translate() XPath function
9428 * string translate(string, string, string)
9429 * The translate function returns the first argument string with
9430 * occurrences of characters in the second argument string replaced
9431 * by the character at the corresponding position in the third argument
9432 * string. For example, translate("bar","abc","ABC") returns the string
9433 * BAr. If there is a character in the second argument string with no
9434 * character at a corresponding position in the third argument string
9435 * (because the second argument string is longer than the third argument
9436 * string), then occurrences of that character in the first argument
9437 * string are removed. For example, translate("--aaa--","abc-","ABC")
9438 * returns "AAA". If a character occurs more than once in second
9439 * argument string, then the first occurrence determines the replacement
9440 * character. If the third argument string is longer than the second
9441 * argument string, then excess characters are ignored.
9442 */
9443void
9444xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009445 xmlXPathObjectPtr str;
9446 xmlXPathObjectPtr from;
9447 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009448 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009449 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009450 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009451 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009452 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009453
Daniel Veillarde043ee12001-04-16 14:08:07 +00009454 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009455
Daniel Veillarde043ee12001-04-16 14:08:07 +00009456 CAST_TO_STRING;
9457 to = valuePop(ctxt);
9458 CAST_TO_STRING;
9459 from = valuePop(ctxt);
9460 CAST_TO_STRING;
9461 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009462
Daniel Veillardade10f22012-07-12 09:43:27 +08009463 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009464 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009465 max = xmlUTF8Strlen(to->stringval);
9466 for (cptr = str->stringval; (ch=*cptr); ) {
9467 offset = xmlUTF8Strloc(from->stringval, cptr);
9468 if (offset >= 0) {
9469 if (offset < max) {
9470 point = xmlUTF8Strpos(to->stringval, offset);
9471 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009472 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009473 }
9474 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009475 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009476
9477 /* Step to next character in input */
9478 cptr++;
9479 if ( ch & 0x80 ) {
9480 /* if not simple ascii, verify proper format */
9481 if ( (ch & 0xc0) != 0xc0 ) {
9482 xmlGenericError(xmlGenericErrorContext,
9483 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009484 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009485 break;
9486 }
9487 /* then skip over remaining bytes for this char */
9488 while ( (ch <<= 1) & 0x80 )
9489 if ( (*cptr++ & 0xc0) != 0x80 ) {
9490 xmlGenericError(xmlGenericErrorContext,
9491 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009492 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009493 break;
9494 }
9495 if (ch & 0x80) /* must have had error encountered */
9496 break;
9497 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009498 }
Owen Taylor3473f882001-02-23 17:55:21 +00009499 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009500 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009501 xmlBufContent(target)));
9502 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009503 xmlXPathReleaseObject(ctxt->context, str);
9504 xmlXPathReleaseObject(ctxt->context, from);
9505 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009506}
9507
9508/**
9509 * xmlXPathBooleanFunction:
9510 * @ctxt: the XPath Parser context
9511 * @nargs: the number of arguments
9512 *
9513 * Implement the boolean() XPath function
9514 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009515 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009516 * - a number is true if and only if it is neither positive or
9517 * negative zero nor NaN
9518 * - a node-set is true if and only if it is non-empty
9519 * - a string is true if and only if its length is non-zero
9520 */
9521void
9522xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9523 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009524
9525 CHECK_ARITY(1);
9526 cur = valuePop(ctxt);
9527 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009528 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009529 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009530}
9531
9532/**
9533 * xmlXPathNotFunction:
9534 * @ctxt: the XPath Parser context
9535 * @nargs: the number of arguments
9536 *
9537 * Implement the not() XPath function
9538 * boolean not(boolean)
9539 * The not function returns true if its argument is false,
9540 * and false otherwise.
9541 */
9542void
9543xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9544 CHECK_ARITY(1);
9545 CAST_TO_BOOLEAN;
9546 CHECK_TYPE(XPATH_BOOLEAN);
9547 ctxt->value->boolval = ! ctxt->value->boolval;
9548}
9549
9550/**
9551 * xmlXPathTrueFunction:
9552 * @ctxt: the XPath Parser context
9553 * @nargs: the number of arguments
9554 *
9555 * Implement the true() XPath function
9556 * boolean true()
9557 */
9558void
9559xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9560 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009561 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009562}
9563
9564/**
9565 * xmlXPathFalseFunction:
9566 * @ctxt: the XPath Parser context
9567 * @nargs: the number of arguments
9568 *
9569 * Implement the false() XPath function
9570 * boolean false()
9571 */
9572void
9573xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9574 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009575 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009576}
9577
9578/**
9579 * xmlXPathLangFunction:
9580 * @ctxt: the XPath Parser context
9581 * @nargs: the number of arguments
9582 *
9583 * Implement the lang() XPath function
9584 * boolean lang(string)
9585 * The lang function returns true or false depending on whether the
9586 * language of the context node as specified by xml:lang attributes
9587 * is the same as or is a sublanguage of the language specified by
9588 * the argument string. The language of the context node is determined
9589 * by the value of the xml:lang attribute on the context node, or, if
9590 * the context node has no xml:lang attribute, by the value of the
9591 * xml:lang attribute on the nearest ancestor of the context node that
9592 * has an xml:lang attribute. If there is no such attribute, then lang
9593 * returns false. If there is such an attribute, then lang returns
9594 * true if the attribute value is equal to the argument ignoring case,
9595 * or if there is some suffix starting with - such that the attribute
9596 * value is equal to the argument ignoring that suffix of the attribute
9597 * value and ignoring case.
9598 */
9599void
9600xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009601 xmlXPathObjectPtr val = NULL;
9602 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009603 const xmlChar *lang;
9604 int ret = 0;
9605 int i;
9606
9607 CHECK_ARITY(1);
9608 CAST_TO_STRING;
9609 CHECK_TYPE(XPATH_STRING);
9610 val = valuePop(ctxt);
9611 lang = val->stringval;
9612 theLang = xmlNodeGetLang(ctxt->context->node);
9613 if ((theLang != NULL) && (lang != NULL)) {
9614 for (i = 0;lang[i] != 0;i++)
9615 if (toupper(lang[i]) != toupper(theLang[i]))
9616 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009617 if ((theLang[i] == 0) || (theLang[i] == '-'))
9618 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009619 }
9620not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009621 if (theLang != NULL)
9622 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009623
9624 xmlXPathReleaseObject(ctxt->context, val);
9625 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009626}
9627
9628/**
9629 * xmlXPathNumberFunction:
9630 * @ctxt: the XPath Parser context
9631 * @nargs: the number of arguments
9632 *
9633 * Implement the number() XPath function
9634 * number number(object?)
9635 */
9636void
9637xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9638 xmlXPathObjectPtr cur;
9639 double res;
9640
Daniel Veillarda82b1822004-11-08 16:24:57 +00009641 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009642 if (nargs == 0) {
9643 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009644 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009645 } else {
9646 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9647
9648 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009649 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009650 xmlFree(content);
9651 }
9652 return;
9653 }
9654
9655 CHECK_ARITY(1);
9656 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009657 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009658}
9659
9660/**
9661 * xmlXPathSumFunction:
9662 * @ctxt: the XPath Parser context
9663 * @nargs: the number of arguments
9664 *
9665 * Implement the sum() XPath function
9666 * number sum(node-set)
9667 * The sum function returns the sum of the values of the nodes in
9668 * the argument node-set.
9669 */
9670void
9671xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9672 xmlXPathObjectPtr cur;
9673 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009674 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009675
9676 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009677 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009678 ((ctxt->value->type != XPATH_NODESET) &&
9679 (ctxt->value->type != XPATH_XSLT_TREE)))
9680 XP_ERROR(XPATH_INVALID_TYPE);
9681 cur = valuePop(ctxt);
9682
William M. Brack08171912003-12-29 02:52:11 +00009683 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009684 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9685 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009686 }
9687 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009688 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9689 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009690}
9691
9692/**
9693 * xmlXPathFloorFunction:
9694 * @ctxt: the XPath Parser context
9695 * @nargs: the number of arguments
9696 *
9697 * Implement the floor() XPath function
9698 * number floor(number)
9699 * The floor function returns the largest (closest to positive infinity)
9700 * number that is not greater than the argument and that is an integer.
9701 */
9702void
9703xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9704 CHECK_ARITY(1);
9705 CAST_TO_NUMBER;
9706 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009707
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009708 ctxt->value->floatval = floor(ctxt->value->floatval);
Owen Taylor3473f882001-02-23 17:55:21 +00009709}
9710
9711/**
9712 * xmlXPathCeilingFunction:
9713 * @ctxt: the XPath Parser context
9714 * @nargs: the number of arguments
9715 *
9716 * Implement the ceiling() XPath function
9717 * number ceiling(number)
9718 * The ceiling function returns the smallest (closest to negative infinity)
9719 * number that is not less than the argument and that is an integer.
9720 */
9721void
9722xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Owen Taylor3473f882001-02-23 17:55:21 +00009723 CHECK_ARITY(1);
9724 CAST_TO_NUMBER;
9725 CHECK_TYPE(XPATH_NUMBER);
9726
Owen Taylor3473f882001-02-23 17:55:21 +00009727 ctxt->value->floatval = ceil(ctxt->value->floatval);
Owen Taylor3473f882001-02-23 17:55:21 +00009728}
9729
9730/**
9731 * xmlXPathRoundFunction:
9732 * @ctxt: the XPath Parser context
9733 * @nargs: the number of arguments
9734 *
9735 * Implement the round() XPath function
9736 * number round(number)
9737 * The round function returns the number that is closest to the
9738 * argument and that is an integer. If there are two such numbers,
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009739 * then the one that is closest to positive infinity is returned.
Owen Taylor3473f882001-02-23 17:55:21 +00009740 */
9741void
9742xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9743 double f;
9744
9745 CHECK_ARITY(1);
9746 CAST_TO_NUMBER;
9747 CHECK_TYPE(XPATH_NUMBER);
9748
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009749 f = ctxt->value->floatval;
9750
9751 /* Test for zero to keep negative zero unchanged. */
9752 if ((xmlXPathIsNaN(f)) || (f == 0.0))
Owen Taylor3473f882001-02-23 17:55:21 +00009753 return;
9754
Nick Wellnhofer4bebb032016-04-21 13:41:09 +02009755 if ((f >= -0.5) && (f < 0.0)) {
9756 /* Negative zero. */
9757 ctxt->value->floatval = xmlXPathNZERO;
9758 }
9759 else {
9760 double rounded = floor(f);
9761 if (f - rounded >= 0.5)
9762 rounded += 1.0;
9763 ctxt->value->floatval = rounded;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009764 }
Owen Taylor3473f882001-02-23 17:55:21 +00009765}
9766
9767/************************************************************************
9768 * *
9769 * The Parser *
9770 * *
9771 ************************************************************************/
9772
9773/*
William M. Brack08171912003-12-29 02:52:11 +00009774 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009775 * implementation.
9776 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009777static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009778static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009779static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009780static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009781static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9782 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009783
9784/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009785 * xmlXPathCurrentChar:
9786 * @ctxt: the XPath parser context
9787 * @cur: pointer to the beginning of the char
9788 * @len: pointer to the length of the char read
9789 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009790 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009791 * bytes in the input buffer.
9792 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009793 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009794 */
9795
9796static int
9797xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9798 unsigned char c;
9799 unsigned int val;
9800 const xmlChar *cur;
9801
9802 if (ctxt == NULL)
9803 return(0);
9804 cur = ctxt->cur;
9805
9806 /*
9807 * We are supposed to handle UTF8, check it's valid
9808 * From rfc2044: encoding of the Unicode values on UTF-8:
9809 *
9810 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9811 * 0000 0000-0000 007F 0xxxxxxx
9812 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009813 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009814 *
9815 * Check for the 0x110000 limit too
9816 */
9817 c = *cur;
9818 if (c & 0x80) {
9819 if ((cur[1] & 0xc0) != 0x80)
9820 goto encoding_error;
9821 if ((c & 0xe0) == 0xe0) {
9822
9823 if ((cur[2] & 0xc0) != 0x80)
9824 goto encoding_error;
9825 if ((c & 0xf0) == 0xf0) {
9826 if (((c & 0xf8) != 0xf0) ||
9827 ((cur[3] & 0xc0) != 0x80))
9828 goto encoding_error;
9829 /* 4-byte code */
9830 *len = 4;
9831 val = (cur[0] & 0x7) << 18;
9832 val |= (cur[1] & 0x3f) << 12;
9833 val |= (cur[2] & 0x3f) << 6;
9834 val |= cur[3] & 0x3f;
9835 } else {
9836 /* 3-byte code */
9837 *len = 3;
9838 val = (cur[0] & 0xf) << 12;
9839 val |= (cur[1] & 0x3f) << 6;
9840 val |= cur[2] & 0x3f;
9841 }
9842 } else {
9843 /* 2-byte code */
9844 *len = 2;
9845 val = (cur[0] & 0x1f) << 6;
9846 val |= cur[1] & 0x3f;
9847 }
9848 if (!IS_CHAR(val)) {
9849 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009850 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009851 return(val);
9852 } else {
9853 /* 1-byte code */
9854 *len = 1;
9855 return((int) *cur);
9856 }
9857encoding_error:
9858 /*
William M. Brack08171912003-12-29 02:52:11 +00009859 * If we detect an UTF8 error that probably means that the
9860 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009861 * declaration header. Report the error and switch the encoding
9862 * to ISO-Latin-1 (if you don't like this policy, just declare the
9863 * encoding !)
9864 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009865 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009866 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009867}
9868
9869/**
Owen Taylor3473f882001-02-23 17:55:21 +00009870 * xmlXPathParseNCName:
9871 * @ctxt: the XPath Parser context
9872 *
9873 * parse an XML namespace non qualified name.
9874 *
9875 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9876 *
9877 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9878 * CombiningChar | Extender
9879 *
9880 * Returns the namespace name or NULL
9881 */
9882
9883xmlChar *
9884xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009885 const xmlChar *in;
9886 xmlChar *ret;
9887 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009888
Daniel Veillarda82b1822004-11-08 16:24:57 +00009889 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009890 /*
9891 * Accelerator for simple ASCII names
9892 */
9893 in = ctxt->cur;
9894 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9895 ((*in >= 0x41) && (*in <= 0x5A)) ||
9896 (*in == '_')) {
9897 in++;
9898 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9899 ((*in >= 0x41) && (*in <= 0x5A)) ||
9900 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009901 (*in == '_') || (*in == '.') ||
9902 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009903 in++;
9904 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9905 (*in == '[') || (*in == ']') || (*in == ':') ||
9906 (*in == '@') || (*in == '*')) {
9907 count = in - ctxt->cur;
9908 if (count == 0)
9909 return(NULL);
9910 ret = xmlStrndup(ctxt->cur, count);
9911 ctxt->cur = in;
9912 return(ret);
9913 }
9914 }
9915 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009916}
9917
Daniel Veillard2156a562001-04-28 12:24:34 +00009918
Owen Taylor3473f882001-02-23 17:55:21 +00009919/**
9920 * xmlXPathParseQName:
9921 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009922 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009923 *
9924 * parse an XML qualified name
9925 *
9926 * [NS 5] QName ::= (Prefix ':')? LocalPart
9927 *
9928 * [NS 6] Prefix ::= NCName
9929 *
9930 * [NS 7] LocalPart ::= NCName
9931 *
9932 * Returns the function returns the local part, and prefix is updated
9933 * to get the Prefix if any.
9934 */
9935
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009936static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009937xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9938 xmlChar *ret = NULL;
9939
9940 *prefix = NULL;
9941 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009942 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009943 *prefix = ret;
9944 NEXT;
9945 ret = xmlXPathParseNCName(ctxt);
9946 }
9947 return(ret);
9948}
9949
9950/**
9951 * xmlXPathParseName:
9952 * @ctxt: the XPath Parser context
9953 *
9954 * parse an XML name
9955 *
9956 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9957 * CombiningChar | Extender
9958 *
9959 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9960 *
9961 * Returns the namespace name or NULL
9962 */
9963
9964xmlChar *
9965xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009966 const xmlChar *in;
9967 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009968 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009969
Daniel Veillarda82b1822004-11-08 16:24:57 +00009970 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009971 /*
9972 * Accelerator for simple ASCII names
9973 */
9974 in = ctxt->cur;
9975 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9976 ((*in >= 0x41) && (*in <= 0x5A)) ||
9977 (*in == '_') || (*in == ':')) {
9978 in++;
9979 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9980 ((*in >= 0x41) && (*in <= 0x5A)) ||
9981 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009982 (*in == '_') || (*in == '-') ||
9983 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009984 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009985 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009986 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009987 if (count > XML_MAX_NAME_LENGTH) {
9988 ctxt->cur = in;
9989 XP_ERRORNULL(XPATH_EXPR_ERROR);
9990 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009991 ret = xmlStrndup(ctxt->cur, count);
9992 ctxt->cur = in;
9993 return(ret);
9994 }
9995 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009996 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009997}
9998
Daniel Veillard61d80a22001-04-27 17:13:01 +00009999static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +000010000xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +000010001 xmlChar buf[XML_MAX_NAMELEN + 5];
10002 int len = 0, l;
10003 int c;
10004
10005 /*
10006 * Handler for more complex cases
10007 */
10008 c = CUR_CHAR(l);
10009 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +000010010 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
10011 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +000010012 (!IS_LETTER(c) && (c != '_') &&
Nick Wellnhofere2893902016-04-21 19:19:23 +020010013 ((!qualified) || (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +000010014 return(NULL);
10015 }
10016
10017 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10018 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10019 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010020 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +000010021 (IS_COMBINING(c)) ||
10022 (IS_EXTENDER(c)))) {
10023 COPY_BUF(l,buf,len,c);
10024 NEXTL(l);
10025 c = CUR_CHAR(l);
10026 if (len >= XML_MAX_NAMELEN) {
10027 /*
10028 * Okay someone managed to make a huge name, so he's ready to pay
10029 * for the processing speed.
10030 */
10031 xmlChar *buffer;
10032 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010033
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010034 if (len > XML_MAX_NAME_LENGTH) {
10035 XP_ERRORNULL(XPATH_EXPR_ERROR);
10036 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +000010037 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010038 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010039 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010040 }
10041 memcpy(buffer, buf, len);
10042 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10043 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010044 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +000010045 (IS_COMBINING(c)) ||
10046 (IS_EXTENDER(c))) {
10047 if (len + 10 > max) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010048 if (max > XML_MAX_NAME_LENGTH) {
10049 XP_ERRORNULL(XPATH_EXPR_ERROR);
10050 }
Daniel Veillard61d80a22001-04-27 17:13:01 +000010051 max *= 2;
10052 buffer = (xmlChar *) xmlRealloc(buffer,
10053 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010054 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010055 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010056 }
10057 }
10058 COPY_BUF(l,buffer,len,c);
10059 NEXTL(l);
10060 c = CUR_CHAR(l);
10061 }
10062 buffer[len] = 0;
10063 return(buffer);
10064 }
10065 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010066 if (len == 0)
10067 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010068 return(xmlStrndup(buf, len));
10069}
Daniel Veillard3cd72402002-05-13 10:33:30 +000010070
10071#define MAX_FRAC 20
10072
Owen Taylor3473f882001-02-23 17:55:21 +000010073/**
10074 * xmlXPathStringEvalNumber:
10075 * @str: A string to scan
10076 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000010077 * [30a] Float ::= Number ('e' Digits?)?
10078 *
Owen Taylor3473f882001-02-23 17:55:21 +000010079 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010080 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010081 * [31] Digits ::= [0-9]+
10082 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010083 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +000010084 * In complement of the Number expression, this function also handles
10085 * negative values : '-' Number.
10086 *
10087 * Returns the double value.
10088 */
10089double
10090xmlXPathStringEvalNumber(const xmlChar *str) {
10091 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +000010092 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010093 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010094 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010095 int exponent = 0;
10096 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010097#ifdef __GNUC__
10098 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010099 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010100#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010101 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +000010102 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010103 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10104 return(xmlXPathNAN);
10105 }
10106 if (*cur == '-') {
10107 isneg = 1;
10108 cur++;
10109 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010110
10111#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010112 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010113 * tmp/temp is a workaround against a gcc compiler bug
10114 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010115 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010116 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010117 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010118 ret = ret * 10;
10119 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010120 ok = 1;
10121 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010122 temp = (double) tmp;
10123 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010124 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010125#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010126 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010127 while ((*cur >= '0') && (*cur <= '9')) {
10128 ret = ret * 10 + (*cur - '0');
10129 ok = 1;
10130 cur++;
10131 }
10132#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010133
Owen Taylor3473f882001-02-23 17:55:21 +000010134 if (*cur == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010135 int v, frac = 0, max;
Daniel Veillard3cd72402002-05-13 10:33:30 +000010136 double fraction = 0;
10137
Owen Taylor3473f882001-02-23 17:55:21 +000010138 cur++;
10139 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10140 return(xmlXPathNAN);
10141 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010142 while (*cur == '0') {
10143 frac = frac + 1;
10144 cur++;
10145 }
10146 max = frac + MAX_FRAC;
10147 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010148 v = (*cur - '0');
10149 fraction = fraction * 10 + v;
10150 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010151 cur++;
10152 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010153 fraction /= pow(10.0, frac);
Daniel Veillard3cd72402002-05-13 10:33:30 +000010154 ret = ret + fraction;
10155 while ((*cur >= '0') && (*cur <= '9'))
10156 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010157 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010158 if ((*cur == 'e') || (*cur == 'E')) {
10159 cur++;
10160 if (*cur == '-') {
10161 is_exponent_negative = 1;
10162 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010163 } else if (*cur == '+') {
10164 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010165 }
10166 while ((*cur >= '0') && (*cur <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010167 if (exponent < 1000000)
10168 exponent = exponent * 10 + (*cur - '0');
Bjorn Reese70a9da52001-04-21 16:57:29 +000010169 cur++;
10170 }
10171 }
William M. Brack76e95df2003-10-18 16:20:14 +000010172 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010173 if (*cur != 0) return(xmlXPathNAN);
10174 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010175 if (is_exponent_negative) exponent = -exponent;
10176 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010177 return(ret);
10178}
10179
10180/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010181 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010182 * @ctxt: the XPath Parser context
10183 *
10184 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010185 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010186 * [31] Digits ::= [0-9]+
10187 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010188 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010189 *
10190 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010191static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010192xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10193{
Owen Taylor3473f882001-02-23 17:55:21 +000010194 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010195 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010196 int exponent = 0;
10197 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010198#ifdef __GNUC__
10199 unsigned long tmp = 0;
10200 double temp;
10201#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010202
10203 CHECK_ERROR;
10204 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10205 XP_ERROR(XPATH_NUMBER_ERROR);
10206 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010207#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010208 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010209 * tmp/temp is a workaround against a gcc compiler bug
10210 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010211 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010212 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010213 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010214 ret = ret * 10;
10215 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010216 ok = 1;
10217 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010218 temp = (double) tmp;
10219 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010220 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010221#else
10222 ret = 0;
10223 while ((CUR >= '0') && (CUR <= '9')) {
10224 ret = ret * 10 + (CUR - '0');
10225 ok = 1;
10226 NEXT;
10227 }
10228#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010229 if (CUR == '.') {
Nick Wellnhofera8518682017-05-29 20:14:42 +020010230 int v, frac = 0, max;
Phil Shaferee32ad32010-11-03 20:53:55 +010010231 double fraction = 0;
10232
Owen Taylor3473f882001-02-23 17:55:21 +000010233 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010234 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10235 XP_ERROR(XPATH_NUMBER_ERROR);
10236 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010237 while (CUR == '0') {
10238 frac = frac + 1;
10239 NEXT;
10240 }
10241 max = frac + MAX_FRAC;
10242 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
Phil Shaferee32ad32010-11-03 20:53:55 +010010243 v = (CUR - '0');
10244 fraction = fraction * 10 + v;
10245 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010246 NEXT;
10247 }
Nick Wellnhofera8518682017-05-29 20:14:42 +020010248 fraction /= pow(10.0, frac);
Phil Shaferee32ad32010-11-03 20:53:55 +010010249 ret = ret + fraction;
10250 while ((CUR >= '0') && (CUR <= '9'))
10251 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010252 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010253 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010254 NEXT;
10255 if (CUR == '-') {
10256 is_exponent_negative = 1;
10257 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010258 } else if (CUR == '+') {
10259 NEXT;
10260 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010261 while ((CUR >= '0') && (CUR <= '9')) {
Nick Wellnhoferf4029cd2016-04-21 16:37:26 +020010262 if (exponent < 1000000)
10263 exponent = exponent * 10 + (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010264 NEXT;
10265 }
10266 if (is_exponent_negative)
10267 exponent = -exponent;
10268 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010269 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010270 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010271 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010272}
10273
10274/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010275 * xmlXPathParseLiteral:
10276 * @ctxt: the XPath Parser context
10277 *
10278 * Parse a Literal
10279 *
10280 * [29] Literal ::= '"' [^"]* '"'
10281 * | "'" [^']* "'"
10282 *
10283 * Returns the value found or NULL in case of error
10284 */
10285static xmlChar *
10286xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10287 const xmlChar *q;
10288 xmlChar *ret = NULL;
10289
10290 if (CUR == '"') {
10291 NEXT;
10292 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010293 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010294 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010295 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010296 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010297 } else {
10298 ret = xmlStrndup(q, CUR_PTR - q);
10299 NEXT;
10300 }
10301 } else if (CUR == '\'') {
10302 NEXT;
10303 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010304 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010305 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010306 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010307 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010308 } else {
10309 ret = xmlStrndup(q, CUR_PTR - q);
10310 NEXT;
10311 }
10312 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010313 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010314 }
10315 return(ret);
10316}
10317
10318/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010319 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010320 * @ctxt: the XPath Parser context
10321 *
10322 * Parse a Literal and push it on the stack.
10323 *
10324 * [29] Literal ::= '"' [^"]* '"'
10325 * | "'" [^']* "'"
10326 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010327 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010328 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010329static void
10330xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010331 const xmlChar *q;
10332 xmlChar *ret = NULL;
10333
10334 if (CUR == '"') {
10335 NEXT;
10336 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010337 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010338 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010339 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010340 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10341 } else {
10342 ret = xmlStrndup(q, CUR_PTR - q);
10343 NEXT;
10344 }
10345 } else if (CUR == '\'') {
10346 NEXT;
10347 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010348 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010349 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010350 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010351 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10352 } else {
10353 ret = xmlStrndup(q, CUR_PTR - q);
10354 NEXT;
10355 }
10356 } else {
10357 XP_ERROR(XPATH_START_LITERAL_ERROR);
10358 }
10359 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010360 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010361 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010362 xmlFree(ret);
10363}
10364
10365/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010366 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010367 * @ctxt: the XPath Parser context
10368 *
10369 * Parse a VariableReference, evaluate it and push it on the stack.
10370 *
10371 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010372 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010373 * of any of the types that are possible for the value of an expression,
10374 * and may also be of additional types not specified here.
10375 *
10376 * Early evaluation is possible since:
10377 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010378 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010379 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010380 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010381 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010382static void
10383xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010384 xmlChar *name;
10385 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010386
10387 SKIP_BLANKS;
10388 if (CUR != '$') {
10389 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10390 }
10391 NEXT;
10392 name = xmlXPathParseQName(ctxt, &prefix);
10393 if (name == NULL) {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010394 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010395 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10396 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010397 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010398 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10399 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010400 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010401 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
Daniel Veillard47881282012-09-07 14:24:50 +080010402 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
Daniel Veillardb3d14912005-09-04 20:47:39 +000010403 }
Owen Taylor3473f882001-02-23 17:55:21 +000010404}
10405
10406/**
10407 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010408 * @name: a name string
10409 *
10410 * Is the name given a NodeType one.
10411 *
10412 * [38] NodeType ::= 'comment'
10413 * | 'text'
10414 * | 'processing-instruction'
10415 * | 'node'
10416 *
10417 * Returns 1 if true 0 otherwise
10418 */
10419int
10420xmlXPathIsNodeType(const xmlChar *name) {
10421 if (name == NULL)
10422 return(0);
10423
Daniel Veillard1971ee22002-01-31 20:29:19 +000010424 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010425 return(1);
10426 if (xmlStrEqual(name, BAD_CAST "text"))
10427 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010428 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010429 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010430 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010431 return(1);
10432 return(0);
10433}
10434
10435/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010436 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010437 * @ctxt: the XPath Parser context
10438 *
10439 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010440 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010441 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010442 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010443 * pushed on the stack
10444 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010445static void
10446xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010447 xmlChar *name;
10448 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010449 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010450 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010451
10452 name = xmlXPathParseQName(ctxt, &prefix);
10453 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010454 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010455 XP_ERROR(XPATH_EXPR_ERROR);
10456 }
10457 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010458#ifdef DEBUG_EXPR
10459 if (prefix == NULL)
10460 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10461 name);
10462 else
10463 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10464 prefix, name);
10465#endif
10466
Owen Taylor3473f882001-02-23 17:55:21 +000010467 if (CUR != '(') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010468 xmlFree(name);
10469 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010470 XP_ERROR(XPATH_EXPR_ERROR);
10471 }
10472 NEXT;
10473 SKIP_BLANKS;
10474
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010475 /*
10476 * Optimization for count(): we don't need the node-set to be sorted.
10477 */
10478 if ((prefix == NULL) && (name[0] == 'c') &&
10479 xmlStrEqual(name, BAD_CAST "count"))
10480 {
10481 sort = 0;
10482 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010483 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010484 if (CUR != ')') {
10485 while (CUR != 0) {
10486 int op1 = ctxt->comp->last;
10487 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010488 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010489 if (ctxt->error != XPATH_EXPRESSION_OK) {
10490 xmlFree(name);
10491 xmlFree(prefix);
10492 return;
10493 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010494 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10495 nbargs++;
10496 if (CUR == ')') break;
10497 if (CUR != ',') {
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020010498 xmlFree(name);
10499 xmlFree(prefix);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010500 XP_ERROR(XPATH_EXPR_ERROR);
10501 }
10502 NEXT;
10503 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010504 }
Owen Taylor3473f882001-02-23 17:55:21 +000010505 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010506 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10507 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010508 NEXT;
10509 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010510}
10511
10512/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010513 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010514 * @ctxt: the XPath Parser context
10515 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010516 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010517 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010518 * | Literal
10519 * | Number
10520 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010521 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010522 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010523 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010524static void
10525xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010526 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010527 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010528 else if (CUR == '(') {
10529 NEXT;
10530 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010531 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010532 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010533 if (CUR != ')') {
10534 XP_ERROR(XPATH_EXPR_ERROR);
10535 }
10536 NEXT;
10537 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010538 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010539 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010540 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010541 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010542 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010543 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010544 }
10545 SKIP_BLANKS;
10546}
10547
10548/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010549 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010550 * @ctxt: the XPath Parser context
10551 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010552 * [20] FilterExpr ::= PrimaryExpr
10553 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010554 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010555 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010556 * Square brackets are used to filter expressions in the same way that
10557 * they are used in location paths. It is an error if the expression to
10558 * be filtered does not evaluate to a node-set. The context node list
10559 * used for evaluating the expression in square brackets is the node-set
10560 * to be filtered listed in document order.
10561 */
10562
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010563static void
10564xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10565 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010566 CHECK_ERROR;
10567 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010568
Owen Taylor3473f882001-02-23 17:55:21 +000010569 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010570 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010571 SKIP_BLANKS;
10572 }
10573
Daniel Veillard45490ae2008-07-29 09:13:19 +000010574
Owen Taylor3473f882001-02-23 17:55:21 +000010575}
10576
10577/**
10578 * xmlXPathScanName:
10579 * @ctxt: the XPath Parser context
10580 *
10581 * Trickery: parse an XML name but without consuming the input flow
10582 * Needed to avoid insanity in the parser state.
10583 *
10584 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10585 * CombiningChar | Extender
10586 *
10587 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10588 *
10589 * [6] Names ::= Name (S Name)*
10590 *
10591 * Returns the Name parsed or NULL
10592 */
10593
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010594static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010595xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010596 int len = 0, l;
10597 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010598 const xmlChar *cur;
10599 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010600
Daniel Veillard03226812004-11-01 14:55:21 +000010601 cur = ctxt->cur;
10602
10603 c = CUR_CHAR(l);
10604 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10605 (!IS_LETTER(c) && (c != '_') &&
10606 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010607 return(NULL);
10608 }
10609
Daniel Veillard03226812004-11-01 14:55:21 +000010610 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10611 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10612 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010613 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010614 (IS_COMBINING(c)) ||
10615 (IS_EXTENDER(c)))) {
10616 len += l;
10617 NEXTL(l);
10618 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010619 }
Daniel Veillard03226812004-11-01 14:55:21 +000010620 ret = xmlStrndup(cur, ctxt->cur - cur);
10621 ctxt->cur = cur;
10622 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010623}
10624
10625/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010626 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010627 * @ctxt: the XPath Parser context
10628 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010629 * [19] PathExpr ::= LocationPath
10630 * | FilterExpr
10631 * | FilterExpr '/' RelativeLocationPath
10632 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010633 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010634 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010635 * The / operator and // operators combine an arbitrary expression
10636 * and a relative location path. It is an error if the expression
10637 * does not evaluate to a node-set.
10638 * The / operator does composition in the same way as when / is
10639 * used in a location path. As in location paths, // is short for
10640 * /descendant-or-self::node()/.
10641 */
10642
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010643static void
10644xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010645 int lc = 1; /* Should we branch to LocationPath ? */
10646 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10647
10648 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010649 if ((CUR == '$') || (CUR == '(') ||
10650 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010651 (CUR == '\'') || (CUR == '"') ||
10652 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010653 lc = 0;
10654 } else if (CUR == '*') {
10655 /* relative or absolute location path */
10656 lc = 1;
10657 } else if (CUR == '/') {
10658 /* relative or absolute location path */
10659 lc = 1;
10660 } else if (CUR == '@') {
10661 /* relative abbreviated attribute location path */
10662 lc = 1;
10663 } else if (CUR == '.') {
10664 /* relative abbreviated attribute location path */
10665 lc = 1;
10666 } else {
10667 /*
10668 * Problem is finding if we have a name here whether it's:
10669 * - a nodetype
10670 * - a function call in which case it's followed by '('
10671 * - an axis in which case it's followed by ':'
10672 * - a element name
10673 * We do an a priori analysis here rather than having to
10674 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010675 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010676 * read/write/debug.
10677 */
10678 SKIP_BLANKS;
10679 name = xmlXPathScanName(ctxt);
10680 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10681#ifdef DEBUG_STEP
10682 xmlGenericError(xmlGenericErrorContext,
10683 "PathExpr: Axis\n");
10684#endif
10685 lc = 1;
10686 xmlFree(name);
10687 } else if (name != NULL) {
10688 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010689
Daniel Veillard45490ae2008-07-29 09:13:19 +000010690
Owen Taylor3473f882001-02-23 17:55:21 +000010691 while (NXT(len) != 0) {
10692 if (NXT(len) == '/') {
10693 /* element name */
10694#ifdef DEBUG_STEP
10695 xmlGenericError(xmlGenericErrorContext,
10696 "PathExpr: AbbrRelLocation\n");
10697#endif
10698 lc = 1;
10699 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010700 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010701 /* ignore blanks */
10702 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010703 } else if (NXT(len) == ':') {
10704#ifdef DEBUG_STEP
10705 xmlGenericError(xmlGenericErrorContext,
10706 "PathExpr: AbbrRelLocation\n");
10707#endif
10708 lc = 1;
10709 break;
10710 } else if ((NXT(len) == '(')) {
Nick Wellnhofer9ab01a22016-06-28 14:22:23 +020010711 /* Node Type or Function */
Owen Taylor3473f882001-02-23 17:55:21 +000010712 if (xmlXPathIsNodeType(name)) {
10713#ifdef DEBUG_STEP
10714 xmlGenericError(xmlGenericErrorContext,
10715 "PathExpr: Type search\n");
10716#endif
10717 lc = 1;
Nick Wellnhofer9ab01a22016-06-28 14:22:23 +020010718#ifdef LIBXML_XPTR_ENABLED
10719 } else if (ctxt->xptr &&
10720 xmlStrEqual(name, BAD_CAST "range-to")) {
10721 lc = 1;
10722#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010723 } else {
10724#ifdef DEBUG_STEP
10725 xmlGenericError(xmlGenericErrorContext,
10726 "PathExpr: function call\n");
10727#endif
10728 lc = 0;
10729 }
10730 break;
10731 } else if ((NXT(len) == '[')) {
10732 /* element name */
10733#ifdef DEBUG_STEP
10734 xmlGenericError(xmlGenericErrorContext,
10735 "PathExpr: AbbrRelLocation\n");
10736#endif
10737 lc = 1;
10738 break;
10739 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10740 (NXT(len) == '=')) {
10741 lc = 1;
10742 break;
10743 } else {
10744 lc = 1;
10745 break;
10746 }
10747 len++;
10748 }
10749 if (NXT(len) == 0) {
10750#ifdef DEBUG_STEP
10751 xmlGenericError(xmlGenericErrorContext,
10752 "PathExpr: AbbrRelLocation\n");
10753#endif
10754 /* element name */
10755 lc = 1;
10756 }
10757 xmlFree(name);
10758 } else {
William M. Brack08171912003-12-29 02:52:11 +000010759 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010760 XP_ERROR(XPATH_EXPR_ERROR);
10761 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010762 }
Owen Taylor3473f882001-02-23 17:55:21 +000010763
10764 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010765 if (CUR == '/') {
10766 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10767 } else {
10768 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010769 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010770 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010771 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010772 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010773 CHECK_ERROR;
10774 if ((CUR == '/') && (NXT(1) == '/')) {
10775 SKIP(2);
10776 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010777
10778 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10779 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10780 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10781
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010782 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010783 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010784 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010785 }
10786 }
10787 SKIP_BLANKS;
10788}
10789
10790/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010791 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010792 * @ctxt: the XPath Parser context
10793 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010794 * [18] UnionExpr ::= PathExpr
10795 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010796 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010797 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010798 */
10799
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010800static void
10801xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10802 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010803 CHECK_ERROR;
10804 SKIP_BLANKS;
10805 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010806 int op1 = ctxt->comp->last;
10807 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010808
10809 NEXT;
10810 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010811 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010812
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010813 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10814
Owen Taylor3473f882001-02-23 17:55:21 +000010815 SKIP_BLANKS;
10816 }
Owen Taylor3473f882001-02-23 17:55:21 +000010817}
10818
10819/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010820 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010821 * @ctxt: the XPath Parser context
10822 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010823 * [27] UnaryExpr ::= UnionExpr
10824 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010825 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010826 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010827 */
10828
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010829static void
10830xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010831 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010832 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010833
10834 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010835 while (CUR == '-') {
10836 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010837 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010838 NEXT;
10839 SKIP_BLANKS;
10840 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010841
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010842 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010843 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010844 if (found) {
10845 if (minus)
10846 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10847 else
10848 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010849 }
10850}
10851
10852/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010853 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010854 * @ctxt: the XPath Parser context
10855 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010856 * [26] MultiplicativeExpr ::= UnaryExpr
10857 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10858 * | MultiplicativeExpr 'div' UnaryExpr
10859 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010860 * [34] MultiplyOperator ::= '*'
10861 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010862 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010863 */
10864
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010865static void
10866xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10867 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010868 CHECK_ERROR;
10869 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010870 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010871 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10872 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10873 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010874 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010875
10876 if (CUR == '*') {
10877 op = 0;
10878 NEXT;
10879 } else if (CUR == 'd') {
10880 op = 1;
10881 SKIP(3);
10882 } else if (CUR == 'm') {
10883 op = 2;
10884 SKIP(3);
10885 }
10886 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010887 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010888 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010889 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010890 SKIP_BLANKS;
10891 }
10892}
10893
10894/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010895 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010896 * @ctxt: the XPath Parser context
10897 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010898 * [25] AdditiveExpr ::= MultiplicativeExpr
10899 * | AdditiveExpr '+' MultiplicativeExpr
10900 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010901 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010902 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010903 */
10904
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010905static void
10906xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010907
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010908 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010909 CHECK_ERROR;
10910 SKIP_BLANKS;
10911 while ((CUR == '+') || (CUR == '-')) {
10912 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010913 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010914
10915 if (CUR == '+') plus = 1;
10916 else plus = 0;
10917 NEXT;
10918 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010919 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010920 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010921 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010922 SKIP_BLANKS;
10923 }
10924}
10925
10926/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010927 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010928 * @ctxt: the XPath Parser context
10929 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010930 * [24] RelationalExpr ::= AdditiveExpr
10931 * | RelationalExpr '<' AdditiveExpr
10932 * | RelationalExpr '>' AdditiveExpr
10933 * | RelationalExpr '<=' AdditiveExpr
10934 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010935 *
10936 * A <= B > C is allowed ? Answer from James, yes with
10937 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10938 * which is basically what got implemented.
10939 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010940 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010941 * on the stack
10942 */
10943
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010944static void
10945xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10946 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010947 CHECK_ERROR;
10948 SKIP_BLANKS;
10949 while ((CUR == '<') ||
10950 (CUR == '>') ||
10951 ((CUR == '<') && (NXT(1) == '=')) ||
10952 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010953 int inf, strict;
10954 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010955
10956 if (CUR == '<') inf = 1;
10957 else inf = 0;
10958 if (NXT(1) == '=') strict = 0;
10959 else strict = 1;
10960 NEXT;
10961 if (!strict) NEXT;
10962 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010963 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010964 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010965 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010966 SKIP_BLANKS;
10967 }
10968}
10969
10970/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010971 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010972 * @ctxt: the XPath Parser context
10973 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010974 * [23] EqualityExpr ::= RelationalExpr
10975 * | EqualityExpr '=' RelationalExpr
10976 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010977 *
10978 * A != B != C is allowed ? Answer from James, yes with
10979 * (RelationalExpr = RelationalExpr) = RelationalExpr
10980 * (RelationalExpr != RelationalExpr) != RelationalExpr
10981 * which is basically what got implemented.
10982 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010983 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010984 *
10985 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010986static void
10987xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10988 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010989 CHECK_ERROR;
10990 SKIP_BLANKS;
10991 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010992 int eq;
10993 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010994
10995 if (CUR == '=') eq = 1;
10996 else eq = 0;
10997 NEXT;
10998 if (!eq) NEXT;
10999 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011000 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011001 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011002 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011003 SKIP_BLANKS;
11004 }
11005}
11006
11007/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011008 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000011009 * @ctxt: the XPath Parser context
11010 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011011 * [22] AndExpr ::= EqualityExpr
11012 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000011013 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011014 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000011015 *
11016 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011017static void
11018xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11019 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011020 CHECK_ERROR;
11021 SKIP_BLANKS;
11022 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011023 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011024 SKIP(3);
11025 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011026 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011027 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011028 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011029 SKIP_BLANKS;
11030 }
11031}
11032
11033/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000011034 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000011035 * @ctxt: the XPath Parser context
11036 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011037 * [14] Expr ::= OrExpr
11038 * [21] OrExpr ::= AndExpr
11039 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000011040 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011041 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000011042 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011043static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011044xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011045 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011046 CHECK_ERROR;
11047 SKIP_BLANKS;
11048 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011049 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011050 SKIP(2);
11051 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011052 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011053 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011054 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011055 SKIP_BLANKS;
11056 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011057 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011058 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011059 /*
11060 * This is the main place to eliminate sorting for
11061 * operations which don't require a sorted node-set.
11062 * E.g. count().
11063 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011064 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11065 }
Owen Taylor3473f882001-02-23 17:55:21 +000011066}
11067
11068/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011069 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000011070 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011071 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000011072 *
11073 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000011074 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000011075 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011076 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000011077 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011078static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011079xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011080 int op1 = ctxt->comp->last;
11081
11082 SKIP_BLANKS;
11083 if (CUR != '[') {
11084 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11085 }
11086 NEXT;
11087 SKIP_BLANKS;
11088
11089 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011090 /*
11091 * This call to xmlXPathCompileExpr() will deactivate sorting
11092 * of the predicate result.
11093 * TODO: Sorting is still activated for filters, since I'm not
11094 * sure if needed. Normally sorting should not be needed, since
11095 * a filter can only diminish the number of items in a sequence,
11096 * but won't change its order; so if the initial sequence is sorted,
11097 * subsequent sorting is not needed.
11098 */
11099 if (! filter)
11100 xmlXPathCompileExpr(ctxt, 0);
11101 else
11102 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011103 CHECK_ERROR;
11104
11105 if (CUR != ']') {
11106 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11107 }
11108
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011109 if (filter)
11110 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11111 else
11112 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011113
11114 NEXT;
11115 SKIP_BLANKS;
11116}
11117
11118/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011119 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011120 * @ctxt: the XPath Parser context
11121 * @test: pointer to a xmlXPathTestVal
11122 * @type: pointer to a xmlXPathTypeVal
11123 * @prefix: placeholder for a possible name prefix
11124 *
11125 * [7] NodeTest ::= NameTest
11126 * | NodeType '(' ')'
11127 * | 'processing-instruction' '(' Literal ')'
11128 *
11129 * [37] NameTest ::= '*'
11130 * | NCName ':' '*'
11131 * | QName
11132 * [38] NodeType ::= 'comment'
11133 * | 'text'
11134 * | 'processing-instruction'
11135 * | 'node'
11136 *
William M. Brack08171912003-12-29 02:52:11 +000011137 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011138 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011139static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011140xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11141 xmlXPathTypeVal *type, const xmlChar **prefix,
11142 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011143 int blanks;
11144
11145 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11146 STRANGE;
11147 return(NULL);
11148 }
William M. Brack78637da2003-07-31 14:47:38 +000011149 *type = (xmlXPathTypeVal) 0;
11150 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011151 *prefix = NULL;
11152 SKIP_BLANKS;
11153
11154 if ((name == NULL) && (CUR == '*')) {
11155 /*
11156 * All elements
11157 */
11158 NEXT;
11159 *test = NODE_TEST_ALL;
11160 return(NULL);
11161 }
11162
11163 if (name == NULL)
11164 name = xmlXPathParseNCName(ctxt);
11165 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011166 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011167 }
11168
William M. Brack76e95df2003-10-18 16:20:14 +000011169 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011170 SKIP_BLANKS;
11171 if (CUR == '(') {
11172 NEXT;
11173 /*
11174 * NodeType or PI search
11175 */
11176 if (xmlStrEqual(name, BAD_CAST "comment"))
11177 *type = NODE_TYPE_COMMENT;
11178 else if (xmlStrEqual(name, BAD_CAST "node"))
11179 *type = NODE_TYPE_NODE;
11180 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11181 *type = NODE_TYPE_PI;
11182 else if (xmlStrEqual(name, BAD_CAST "text"))
11183 *type = NODE_TYPE_TEXT;
11184 else {
11185 if (name != NULL)
11186 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011187 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011188 }
11189
11190 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011191
Owen Taylor3473f882001-02-23 17:55:21 +000011192 SKIP_BLANKS;
11193 if (*type == NODE_TYPE_PI) {
11194 /*
11195 * Specific case: search a PI by name.
11196 */
Owen Taylor3473f882001-02-23 17:55:21 +000011197 if (name != NULL)
11198 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011199 name = NULL;
11200 if (CUR != ')') {
11201 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011202 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011203 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011204 SKIP_BLANKS;
11205 }
Owen Taylor3473f882001-02-23 17:55:21 +000011206 }
11207 if (CUR != ')') {
11208 if (name != NULL)
11209 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011210 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011211 }
11212 NEXT;
11213 return(name);
11214 }
11215 *test = NODE_TEST_NAME;
11216 if ((!blanks) && (CUR == ':')) {
11217 NEXT;
11218
11219 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011220 * Since currently the parser context don't have a
11221 * namespace list associated:
11222 * The namespace name for this prefix can be computed
11223 * only at evaluation time. The compilation is done
11224 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011225 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011226#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011227 *prefix = xmlXPathNsLookup(ctxt->context, name);
11228 if (name != NULL)
11229 xmlFree(name);
11230 if (*prefix == NULL) {
11231 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11232 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011233#else
11234 *prefix = name;
11235#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011236
11237 if (CUR == '*') {
11238 /*
11239 * All elements
11240 */
11241 NEXT;
11242 *test = NODE_TEST_ALL;
11243 return(NULL);
11244 }
11245
11246 name = xmlXPathParseNCName(ctxt);
11247 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011248 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011249 }
11250 }
11251 return(name);
11252}
11253
11254/**
11255 * xmlXPathIsAxisName:
11256 * @name: a preparsed name token
11257 *
11258 * [6] AxisName ::= 'ancestor'
11259 * | 'ancestor-or-self'
11260 * | 'attribute'
11261 * | 'child'
11262 * | 'descendant'
11263 * | 'descendant-or-self'
11264 * | 'following'
11265 * | 'following-sibling'
11266 * | 'namespace'
11267 * | 'parent'
11268 * | 'preceding'
11269 * | 'preceding-sibling'
11270 * | 'self'
11271 *
11272 * Returns the axis or 0
11273 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011274static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011275xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011276 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011277 switch (name[0]) {
11278 case 'a':
11279 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11280 ret = AXIS_ANCESTOR;
11281 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11282 ret = AXIS_ANCESTOR_OR_SELF;
11283 if (xmlStrEqual(name, BAD_CAST "attribute"))
11284 ret = AXIS_ATTRIBUTE;
11285 break;
11286 case 'c':
11287 if (xmlStrEqual(name, BAD_CAST "child"))
11288 ret = AXIS_CHILD;
11289 break;
11290 case 'd':
11291 if (xmlStrEqual(name, BAD_CAST "descendant"))
11292 ret = AXIS_DESCENDANT;
11293 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11294 ret = AXIS_DESCENDANT_OR_SELF;
11295 break;
11296 case 'f':
11297 if (xmlStrEqual(name, BAD_CAST "following"))
11298 ret = AXIS_FOLLOWING;
11299 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11300 ret = AXIS_FOLLOWING_SIBLING;
11301 break;
11302 case 'n':
11303 if (xmlStrEqual(name, BAD_CAST "namespace"))
11304 ret = AXIS_NAMESPACE;
11305 break;
11306 case 'p':
11307 if (xmlStrEqual(name, BAD_CAST "parent"))
11308 ret = AXIS_PARENT;
11309 if (xmlStrEqual(name, BAD_CAST "preceding"))
11310 ret = AXIS_PRECEDING;
11311 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11312 ret = AXIS_PRECEDING_SIBLING;
11313 break;
11314 case 's':
11315 if (xmlStrEqual(name, BAD_CAST "self"))
11316 ret = AXIS_SELF;
11317 break;
11318 }
11319 return(ret);
11320}
11321
11322/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011323 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011324 * @ctxt: the XPath Parser context
11325 *
11326 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011327 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011328 *
11329 * [12] AbbreviatedStep ::= '.' | '..'
11330 *
11331 * [5] AxisSpecifier ::= AxisName '::'
11332 * | AbbreviatedAxisSpecifier
11333 *
11334 * [13] AbbreviatedAxisSpecifier ::= '@'?
11335 *
11336 * Modified for XPtr range support as:
11337 *
11338 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11339 * | AbbreviatedStep
11340 * | 'range-to' '(' Expr ')' Predicate*
11341 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011342 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011343 * A location step of . is short for self::node(). This is
11344 * particularly useful in conjunction with //. For example, the
11345 * location path .//para is short for
11346 * self::node()/descendant-or-self::node()/child::para
11347 * and so will select all para descendant elements of the context
11348 * node.
11349 * Similarly, a location step of .. is short for parent::node().
11350 * For example, ../title is short for parent::node()/child::title
11351 * and so will select the title children of the parent of the context
11352 * node.
11353 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011354static void
11355xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011356#ifdef LIBXML_XPTR_ENABLED
11357 int rangeto = 0;
11358 int op2 = -1;
11359#endif
11360
Owen Taylor3473f882001-02-23 17:55:21 +000011361 SKIP_BLANKS;
11362 if ((CUR == '.') && (NXT(1) == '.')) {
11363 SKIP(2);
11364 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011365 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11366 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011367 } else if (CUR == '.') {
11368 NEXT;
11369 SKIP_BLANKS;
11370 } else {
11371 xmlChar *name = NULL;
11372 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011373 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011374 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011375 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011376 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011377
11378 /*
11379 * The modification needed for XPointer change to the production
11380 */
11381#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011382 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011383 name = xmlXPathParseNCName(ctxt);
11384 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011385 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011386 xmlFree(name);
11387 SKIP_BLANKS;
11388 if (CUR != '(') {
11389 XP_ERROR(XPATH_EXPR_ERROR);
11390 }
11391 NEXT;
11392 SKIP_BLANKS;
11393
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011394 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011395 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011396 CHECK_ERROR;
11397
11398 SKIP_BLANKS;
11399 if (CUR != ')') {
11400 XP_ERROR(XPATH_EXPR_ERROR);
11401 }
11402 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011403 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011404 goto eval_predicates;
11405 }
11406 }
11407#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011408 if (CUR == '*') {
11409 axis = AXIS_CHILD;
11410 } else {
11411 if (name == NULL)
11412 name = xmlXPathParseNCName(ctxt);
11413 if (name != NULL) {
11414 axis = xmlXPathIsAxisName(name);
11415 if (axis != 0) {
11416 SKIP_BLANKS;
11417 if ((CUR == ':') && (NXT(1) == ':')) {
11418 SKIP(2);
11419 xmlFree(name);
11420 name = NULL;
11421 } else {
11422 /* an element name can conflict with an axis one :-\ */
11423 axis = AXIS_CHILD;
11424 }
Owen Taylor3473f882001-02-23 17:55:21 +000011425 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011426 axis = AXIS_CHILD;
11427 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011428 } else if (CUR == '@') {
11429 NEXT;
11430 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011431 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011432 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011433 }
Owen Taylor3473f882001-02-23 17:55:21 +000011434 }
11435
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011436 if (ctxt->error != XPATH_EXPRESSION_OK) {
11437 xmlFree(name);
11438 return;
11439 }
Owen Taylor3473f882001-02-23 17:55:21 +000011440
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011441 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011442 if (test == 0)
11443 return;
11444
Daniel Veillarded6c5492005-07-23 15:00:22 +000011445 if ((prefix != NULL) && (ctxt->context != NULL) &&
11446 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11447 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11448 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11449 }
11450 }
Owen Taylor3473f882001-02-23 17:55:21 +000011451#ifdef DEBUG_STEP
11452 xmlGenericError(xmlGenericErrorContext,
11453 "Basis : computing new set\n");
11454#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011455
Owen Taylor3473f882001-02-23 17:55:21 +000011456#ifdef DEBUG_STEP
11457 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011458 if (ctxt->value == NULL)
11459 xmlGenericError(xmlGenericErrorContext, "no value\n");
11460 else if (ctxt->value->nodesetval == NULL)
11461 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11462 else
11463 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011464#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011465
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011466#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011467eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011468#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011469 op1 = ctxt->comp->last;
11470 ctxt->comp->last = -1;
11471
Owen Taylor3473f882001-02-23 17:55:21 +000011472 SKIP_BLANKS;
11473 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011474 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011475 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011476
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011477#ifdef LIBXML_XPTR_ENABLED
11478 if (rangeto) {
11479 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11480 } else
11481#endif
11482 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11483 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011484
Owen Taylor3473f882001-02-23 17:55:21 +000011485 }
11486#ifdef DEBUG_STEP
11487 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011488 if (ctxt->value == NULL)
11489 xmlGenericError(xmlGenericErrorContext, "no value\n");
11490 else if (ctxt->value->nodesetval == NULL)
11491 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11492 else
11493 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11494 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011495#endif
11496}
11497
11498/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011499 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011500 * @ctxt: the XPath Parser context
11501 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011502 * [3] RelativeLocationPath ::= Step
11503 * | RelativeLocationPath '/' Step
11504 * | AbbreviatedRelativeLocationPath
11505 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011506 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011507 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011508 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011509static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011510xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011511(xmlXPathParserContextPtr ctxt) {
11512 SKIP_BLANKS;
11513 if ((CUR == '/') && (NXT(1) == '/')) {
11514 SKIP(2);
11515 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011516 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11517 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011518 } else if (CUR == '/') {
11519 NEXT;
11520 SKIP_BLANKS;
11521 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011522 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011523 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011524 SKIP_BLANKS;
11525 while (CUR == '/') {
11526 if ((CUR == '/') && (NXT(1) == '/')) {
11527 SKIP(2);
11528 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011529 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011530 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011531 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011532 } else if (CUR == '/') {
11533 NEXT;
11534 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011535 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011536 }
11537 SKIP_BLANKS;
11538 }
11539}
11540
11541/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011542 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011543 * @ctxt: the XPath Parser context
11544 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011545 * [1] LocationPath ::= RelativeLocationPath
11546 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011547 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011548 * | AbbreviatedAbsoluteLocationPath
11549 * [10] AbbreviatedAbsoluteLocationPath ::=
11550 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011551 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011552 * Compile a location path
11553 *
Owen Taylor3473f882001-02-23 17:55:21 +000011554 * // is short for /descendant-or-self::node()/. For example,
11555 * //para is short for /descendant-or-self::node()/child::para and
11556 * so will select any para element in the document (even a para element
11557 * that is a document element will be selected by //para since the
11558 * document element node is a child of the root node); div//para is
11559 * short for div/descendant-or-self::node()/child::para and so will
11560 * select all para descendants of div children.
11561 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011562static void
11563xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011564 SKIP_BLANKS;
11565 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011566 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011567 } else {
11568 while (CUR == '/') {
11569 if ((CUR == '/') && (NXT(1) == '/')) {
11570 SKIP(2);
11571 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011572 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11573 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011574 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011575 } else if (CUR == '/') {
11576 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011577 SKIP_BLANKS;
11578 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011579 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011580 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011581 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011582 }
Martin729601f2009-10-12 22:42:26 +020011583 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011584 }
11585 }
11586}
11587
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011588/************************************************************************
11589 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011590 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011591 * *
11592 ************************************************************************/
11593
Daniel Veillardf06307e2001-07-03 10:35:50 +000011594static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011595xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11596
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011597#ifdef DEBUG_STEP
11598static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011599xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011600 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011601{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011602 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011603 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011604 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011605 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011606 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011607 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011608 xmlGenericError(xmlGenericErrorContext,
11609 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011610 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011611 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011612 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011613 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011614 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011615 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011616 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011617 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011618 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011619 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011620 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011621 xmlGenericError(xmlGenericErrorContext,
11622 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011623 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011624 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011625 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011626 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011627 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011628 xmlGenericError(xmlGenericErrorContext,
11629 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011630 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011631 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011632 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011633 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011634 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011635 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011636 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011637 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011638 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011639 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011640 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011641 xmlGenericError(xmlGenericErrorContext,
11642 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011643 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011644 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011645 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011646 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011647 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011648 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011649 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011650 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011651 case NODE_TEST_NONE:
11652 xmlGenericError(xmlGenericErrorContext,
11653 " searching for none !!!\n");
11654 break;
11655 case NODE_TEST_TYPE:
11656 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011657 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011658 break;
11659 case NODE_TEST_PI:
11660 xmlGenericError(xmlGenericErrorContext,
11661 " searching for PI !!!\n");
11662 break;
11663 case NODE_TEST_ALL:
11664 xmlGenericError(xmlGenericErrorContext,
11665 " searching for *\n");
11666 break;
11667 case NODE_TEST_NS:
11668 xmlGenericError(xmlGenericErrorContext,
11669 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011670 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011671 break;
11672 case NODE_TEST_NAME:
11673 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011674 " searching for name %s\n", op->value5);
11675 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011676 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011677 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011678 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011679 }
11680 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011681}
11682#endif /* DEBUG_STEP */
11683
11684static int
11685xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11686 xmlXPathStepOpPtr op,
11687 xmlNodeSetPtr set,
11688 int contextSize,
11689 int hasNsNodes)
11690{
11691 if (op->ch1 != -1) {
11692 xmlXPathCompExprPtr comp = ctxt->comp;
11693 /*
11694 * Process inner predicates first.
11695 */
11696 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11697 /*
11698 * TODO: raise an internal error.
11699 */
11700 }
11701 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11702 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11703 CHECK_ERROR0;
11704 if (contextSize <= 0)
11705 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011706 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011707 if (op->ch2 != -1) {
11708 xmlXPathContextPtr xpctxt = ctxt->context;
11709 xmlNodePtr contextNode, oldContextNode;
11710 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011711 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011712 xmlXPathStepOpPtr exprOp;
11713 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11714
11715#ifdef LIBXML_XPTR_ENABLED
11716 /*
11717 * URGENT TODO: Check the following:
11718 * We don't expect location sets if evaluating prediates, right?
11719 * Only filters should expect location sets, right?
11720 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011721#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011722 /*
11723 * SPEC XPath 1.0:
11724 * "For each node in the node-set to be filtered, the
11725 * PredicateExpr is evaluated with that node as the
11726 * context node, with the number of nodes in the
11727 * node-set as the context size, and with the proximity
11728 * position of the node in the node-set with respect to
11729 * the axis as the context position;"
11730 * @oldset is the node-set" to be filtered.
11731 *
11732 * SPEC XPath 1.0:
11733 * "only predicates change the context position and
11734 * context size (see [2.4 Predicates])."
11735 * Example:
11736 * node-set context pos
11737 * nA 1
11738 * nB 2
11739 * nC 3
11740 * After applying predicate [position() > 1] :
11741 * node-set context pos
11742 * nB 1
11743 * nC 2
11744 */
11745 oldContextNode = xpctxt->node;
11746 oldContextDoc = xpctxt->doc;
11747 /*
11748 * Get the expression of this predicate.
11749 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011750 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011751 newContextSize = 0;
11752 for (i = 0; i < set->nodeNr; i++) {
11753 if (set->nodeTab[i] == NULL)
11754 continue;
11755
11756 contextNode = set->nodeTab[i];
11757 xpctxt->node = contextNode;
11758 xpctxt->contextSize = contextSize;
11759 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011760
11761 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011762 * Also set the xpath document in case things like
11763 * key() are evaluated in the predicate.
11764 */
11765 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11766 (contextNode->doc != NULL))
11767 xpctxt->doc = contextNode->doc;
11768 /*
11769 * Evaluate the predicate expression with 1 context node
11770 * at a time; this node is packaged into a node set; this
11771 * node set is handed over to the evaluation mechanism.
11772 */
11773 if (contextObj == NULL)
11774 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011775 else {
11776 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11777 contextNode) < 0) {
11778 ctxt->error = XPATH_MEMORY_ERROR;
11779 goto evaluation_exit;
11780 }
11781 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011782
11783 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011784
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011785 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011786
William M. Brack0bcec062007-02-14 02:15:19 +000011787 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11788 xmlXPathNodeSetClear(set, hasNsNodes);
11789 newContextSize = 0;
11790 goto evaluation_exit;
11791 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011792
11793 if (res != 0) {
11794 newContextSize++;
11795 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011796 /*
11797 * Remove the entry from the initial node set.
11798 */
11799 set->nodeTab[i] = NULL;
11800 if (contextNode->type == XML_NAMESPACE_DECL)
11801 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011802 }
11803 if (ctxt->value == contextObj) {
11804 /*
11805 * Don't free the temporary XPath object holding the
11806 * context node, in order to avoid massive recreation
11807 * inside this loop.
11808 */
11809 valuePop(ctxt);
11810 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11811 } else {
11812 /*
11813 * TODO: The object was lost in the evaluation machinery.
11814 * Can this happen? Maybe in internal-error cases.
11815 */
11816 contextObj = NULL;
11817 }
11818 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011819
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011820 if (contextObj != NULL) {
11821 if (ctxt->value == contextObj)
11822 valuePop(ctxt);
11823 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011824 }
William M. Brack0bcec062007-02-14 02:15:19 +000011825evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011826 if (exprRes != NULL)
11827 xmlXPathReleaseObject(ctxt->context, exprRes);
11828 /*
11829 * Reset/invalidate the context.
11830 */
11831 xpctxt->node = oldContextNode;
11832 xpctxt->doc = oldContextDoc;
11833 xpctxt->contextSize = -1;
11834 xpctxt->proximityPosition = -1;
11835 return(newContextSize);
11836 }
11837 return(contextSize);
11838}
11839
11840static int
11841xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11842 xmlXPathStepOpPtr op,
11843 xmlNodeSetPtr set,
11844 int contextSize,
11845 int minPos,
11846 int maxPos,
11847 int hasNsNodes)
11848{
11849 if (op->ch1 != -1) {
11850 xmlXPathCompExprPtr comp = ctxt->comp;
11851 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11852 /*
11853 * TODO: raise an internal error.
11854 */
11855 }
11856 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11857 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11858 CHECK_ERROR0;
11859 if (contextSize <= 0)
11860 return(0);
11861 }
11862 /*
11863 * Check if the node set contains a sufficient number of nodes for
11864 * the requested range.
11865 */
11866 if (contextSize < minPos) {
11867 xmlXPathNodeSetClear(set, hasNsNodes);
11868 return(0);
11869 }
11870 if (op->ch2 == -1) {
11871 /*
11872 * TODO: Can this ever happen?
11873 */
11874 return (contextSize);
11875 } else {
11876 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011877 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011878 xmlXPathStepOpPtr exprOp;
11879 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11880 xmlNodePtr oldContextNode, contextNode = NULL;
11881 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011882 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011883
11884#ifdef LIBXML_XPTR_ENABLED
11885 /*
11886 * URGENT TODO: Check the following:
11887 * We don't expect location sets if evaluating prediates, right?
11888 * Only filters should expect location sets, right?
11889 */
11890#endif /* LIBXML_XPTR_ENABLED */
11891
11892 /*
11893 * Save old context.
11894 */
11895 oldContextNode = xpctxt->node;
11896 oldContextDoc = xpctxt->doc;
11897 /*
11898 * Get the expression of this predicate.
11899 */
11900 exprOp = &ctxt->comp->steps[op->ch2];
11901 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011902 xmlXPathObjectPtr tmp;
11903
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011904 if (set->nodeTab[i] == NULL)
11905 continue;
11906
11907 contextNode = set->nodeTab[i];
11908 xpctxt->node = contextNode;
11909 xpctxt->contextSize = contextSize;
11910 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011911
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011912 /*
11913 * Initialize the new set.
11914 * Also set the xpath document in case things like
11915 * key() evaluation are attempted on the predicate
11916 */
11917 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11918 (contextNode->doc != NULL))
11919 xpctxt->doc = contextNode->doc;
11920 /*
11921 * Evaluate the predicate expression with 1 context node
11922 * at a time; this node is packaged into a node set; this
11923 * node set is handed over to the evaluation mechanism.
11924 */
11925 if (contextObj == NULL)
11926 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011927 else {
11928 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11929 contextNode) < 0) {
11930 ctxt->error = XPATH_MEMORY_ERROR;
11931 goto evaluation_exit;
11932 }
11933 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011934
Daniel Veillardf5048b32011-08-18 17:10:13 +080011935 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011936 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011937 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011938 tmp = valuePop(ctxt);
11939 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011940
William M. Brackf1794562007-08-23 12:58:13 +000011941 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011942 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011943 /*
11944 * Free up the result
11945 * then pop off contextObj, which will be freed later
11946 */
11947 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011948 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011949 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011950 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011951 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011952 /* push the result back onto the stack */
11953 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011954
11955 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011956 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011957
11958 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011959 /*
11960 * Fits in the requested range.
11961 */
11962 newContextSize++;
11963 if (minPos == maxPos) {
11964 /*
11965 * Only 1 node was requested.
11966 */
11967 if (contextNode->type == XML_NAMESPACE_DECL) {
11968 /*
11969 * As always: take care of those nasty
11970 * namespace nodes.
11971 */
11972 set->nodeTab[i] = NULL;
11973 }
11974 xmlXPathNodeSetClear(set, hasNsNodes);
11975 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011976 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011977 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011978 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011979 if (pos == maxPos) {
11980 /*
11981 * We are done.
11982 */
11983 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11984 goto evaluation_exit;
11985 }
11986 } else {
11987 /*
11988 * Remove the entry from the initial node set.
11989 */
11990 set->nodeTab[i] = NULL;
11991 if (contextNode->type == XML_NAMESPACE_DECL)
11992 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11993 }
11994 if (exprRes != NULL) {
11995 xmlXPathReleaseObject(ctxt->context, exprRes);
11996 exprRes = NULL;
11997 }
11998 if (ctxt->value == contextObj) {
11999 /*
12000 * Don't free the temporary XPath object holding the
12001 * context node, in order to avoid massive recreation
12002 * inside this loop.
12003 */
12004 valuePop(ctxt);
12005 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
12006 } else {
12007 /*
12008 * The object was lost in the evaluation machinery.
12009 * Can this happen? Maybe in case of internal-errors.
12010 */
12011 contextObj = NULL;
12012 }
12013 }
12014 goto evaluation_exit;
12015
12016evaluation_error:
12017 xmlXPathNodeSetClear(set, hasNsNodes);
12018 newContextSize = 0;
12019
12020evaluation_exit:
12021 if (contextObj != NULL) {
12022 if (ctxt->value == contextObj)
12023 valuePop(ctxt);
12024 xmlXPathReleaseObject(xpctxt, contextObj);
12025 }
12026 if (exprRes != NULL)
12027 xmlXPathReleaseObject(ctxt->context, exprRes);
12028 /*
12029 * Reset/invalidate the context.
12030 */
12031 xpctxt->node = oldContextNode;
12032 xpctxt->doc = oldContextDoc;
12033 xpctxt->contextSize = -1;
12034 xpctxt->proximityPosition = -1;
12035 return(newContextSize);
12036 }
12037 return(contextSize);
12038}
12039
12040static int
12041xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000012042 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012043 int *maxPos)
12044{
12045
12046 xmlXPathStepOpPtr exprOp;
12047
12048 /*
12049 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12050 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012051
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012052 /*
12053 * If not -1, then ch1 will point to:
12054 * 1) For predicates (XPATH_OP_PREDICATE):
12055 * - an inner predicate operator
12056 * 2) For filters (XPATH_OP_FILTER):
12057 * - an inner filter operater OR
12058 * - an expression selecting the node set.
12059 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012060 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012061 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12062 return(0);
12063
12064 if (op->ch2 != -1) {
12065 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012066 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012067 return(0);
12068
12069 if ((exprOp != NULL) &&
12070 (exprOp->op == XPATH_OP_VALUE) &&
12071 (exprOp->value4 != NULL) &&
12072 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12073 {
Nick Wellnhofera58331a2017-05-29 21:02:21 +020012074 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12075
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012076 /*
12077 * We have a "[n]" predicate here.
12078 * TODO: Unfortunately this simplistic test here is not
12079 * able to detect a position() predicate in compound
12080 * expressions like "[@attr = 'a" and position() = 1],
12081 * and even not the usage of position() in
12082 * "[position() = 1]"; thus - obviously - a position-range,
12083 * like it "[position() < 5]", is also not detected.
12084 * Maybe we could rewrite the AST to ease the optimization.
12085 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012086
Nick Wellnhofera58331a2017-05-29 21:02:21 +020012087 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12088 *maxPos = (int) floatval;
12089 if (floatval == (double) *maxPos)
12090 return(1);
12091 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012092 }
12093 return(0);
12094}
12095
12096static int
12097xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12098 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012099 xmlNodePtr * first, xmlNodePtr * last,
12100 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012101{
12102
12103#define XP_TEST_HIT \
12104 if (hasAxisRange != 0) { \
12105 if (++pos == maxPos) { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012106 if (addNode(seq, cur) < 0) \
12107 ctxt->error = XPATH_MEMORY_ERROR; \
12108 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012109 } else { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012110 if (addNode(seq, cur) < 0) \
12111 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012112 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012113
12114#define XP_TEST_HIT_NS \
12115 if (hasAxisRange != 0) { \
12116 if (++pos == maxPos) { \
12117 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012118 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12119 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012120 goto axis_range_end; } \
12121 } else { \
12122 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012123 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12124 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012125 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012126
12127 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12128 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12129 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12130 const xmlChar *prefix = op->value4;
12131 const xmlChar *name = op->value5;
12132 const xmlChar *URI = NULL;
12133
12134#ifdef DEBUG_STEP
12135 int nbMatches = 0, prevMatches = 0;
12136#endif
12137 int total = 0, hasNsNodes = 0;
12138 /* The popped object holding the context nodes */
12139 xmlXPathObjectPtr obj;
12140 /* The set of context nodes for the node tests */
12141 xmlNodeSetPtr contextSeq;
12142 int contextIdx;
12143 xmlNodePtr contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012144 /* The final resulting node set wrt to all context nodes */
12145 xmlNodeSetPtr outSeq;
12146 /*
12147 * The temporary resulting node set wrt 1 context node.
12148 * Used to feed predicate evaluation.
12149 */
12150 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012151 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012152 /* First predicate operator */
12153 xmlXPathStepOpPtr predOp;
12154 int maxPos; /* The requested position() (when a "[n]" predicate) */
12155 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012156 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012157
12158 xmlXPathTraversalFunction next = NULL;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012159 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012160 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012161 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012162 xmlXPathContextPtr xpctxt = ctxt->context;
12163
12164
12165 CHECK_TYPE0(XPATH_NODESET);
12166 obj = valuePop(ctxt);
12167 /*
12168 * Setup namespaces.
12169 */
12170 if (prefix != NULL) {
12171 URI = xmlXPathNsLookup(xpctxt, prefix);
12172 if (URI == NULL) {
12173 xmlXPathReleaseObject(xpctxt, obj);
12174 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12175 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012176 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012177 /*
12178 * Setup axis.
12179 *
12180 * MAYBE FUTURE TODO: merging optimizations:
12181 * - If the nodes to be traversed wrt to the initial nodes and
12182 * the current axis cannot overlap, then we could avoid searching
12183 * for duplicates during the merge.
12184 * But the question is how/when to evaluate if they cannot overlap.
12185 * Example: if we know that for two initial nodes, the one is
12186 * not in the ancestor-or-self axis of the other, then we could safely
12187 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12188 * the descendant-or-self axis.
12189 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012190 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12191 switch (axis) {
12192 case AXIS_ANCESTOR:
12193 first = NULL;
12194 next = xmlXPathNextAncestor;
12195 break;
12196 case AXIS_ANCESTOR_OR_SELF:
12197 first = NULL;
12198 next = xmlXPathNextAncestorOrSelf;
12199 break;
12200 case AXIS_ATTRIBUTE:
12201 first = NULL;
12202 last = NULL;
12203 next = xmlXPathNextAttribute;
12204 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12205 break;
12206 case AXIS_CHILD:
12207 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012208 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12209 (type == NODE_TYPE_NODE))
12210 {
12211 /*
12212 * Optimization if an element node type is 'element'.
12213 */
12214 next = xmlXPathNextChildElement;
12215 } else
12216 next = xmlXPathNextChild;
12217 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12218 break;
12219 case AXIS_DESCENDANT:
12220 last = NULL;
12221 next = xmlXPathNextDescendant;
12222 break;
12223 case AXIS_DESCENDANT_OR_SELF:
12224 last = NULL;
12225 next = xmlXPathNextDescendantOrSelf;
12226 break;
12227 case AXIS_FOLLOWING:
12228 last = NULL;
12229 next = xmlXPathNextFollowing;
12230 break;
12231 case AXIS_FOLLOWING_SIBLING:
12232 last = NULL;
12233 next = xmlXPathNextFollowingSibling;
12234 break;
12235 case AXIS_NAMESPACE:
12236 first = NULL;
12237 last = NULL;
12238 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12239 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12240 break;
12241 case AXIS_PARENT:
12242 first = NULL;
12243 next = xmlXPathNextParent;
12244 break;
12245 case AXIS_PRECEDING:
12246 first = NULL;
12247 next = xmlXPathNextPrecedingInternal;
12248 break;
12249 case AXIS_PRECEDING_SIBLING:
12250 first = NULL;
12251 next = xmlXPathNextPrecedingSibling;
12252 break;
12253 case AXIS_SELF:
12254 first = NULL;
12255 last = NULL;
12256 next = xmlXPathNextSelf;
12257 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12258 break;
12259 }
12260
12261#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012262 xmlXPathDebugDumpStepAxis(op,
12263 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012264#endif
12265
12266 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012267 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012268 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012269 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012270 contextSeq = obj->nodesetval;
12271 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12272 xmlXPathReleaseObject(xpctxt, obj);
12273 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12274 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012275 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012276 /*
12277 * Predicate optimization ---------------------------------------------
12278 * If this step has a last predicate, which contains a position(),
12279 * then we'll optimize (although not exactly "position()", but only
12280 * the short-hand form, i.e., "[n]".
12281 *
12282 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012283 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012284 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12285 * ROOT -- op->ch1
12286 * PREDICATE -- op->ch2 (predOp)
12287 * PREDICATE -- predOp->ch1 = [parent::bar]
12288 * SORT
12289 * COLLECT 'parent' 'name' 'node' bar
12290 * NODE
12291 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12292 *
12293 */
12294 maxPos = 0;
12295 predOp = NULL;
12296 hasPredicateRange = 0;
12297 hasAxisRange = 0;
12298 if (op->ch2 != -1) {
12299 /*
12300 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12301 */
12302 predOp = &ctxt->comp->steps[op->ch2];
12303 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12304 if (predOp->ch1 != -1) {
12305 /*
12306 * Use the next inner predicate operator.
12307 */
12308 predOp = &ctxt->comp->steps[predOp->ch1];
12309 hasPredicateRange = 1;
12310 } else {
12311 /*
12312 * There's no other predicate than the [n] predicate.
12313 */
12314 predOp = NULL;
12315 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012316 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012317 }
12318 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012319 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012320 /*
12321 * Axis traversal -----------------------------------------------------
12322 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012323 /*
12324 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012325 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012326 * - For the namespace axis, the principal node type is namespace.
12327 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012328 *
12329 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012330 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012331 * select all element children of the context node
12332 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012333 oldContextNode = xpctxt->node;
12334 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012335 outSeq = NULL;
12336 seq = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012337 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012338 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012339
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012340
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012341 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12342 (ctxt->error == XPATH_EXPRESSION_OK)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012343 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012344
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012345 if (seq == NULL) {
12346 seq = xmlXPathNodeSetCreate(NULL);
12347 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012348 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012349 goto error;
12350 }
12351 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012352 /*
12353 * Traverse the axis and test the nodes.
12354 */
12355 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012356 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012357 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012358 do {
12359 cur = next(ctxt, cur);
12360 if (cur == NULL)
12361 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012362
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012363 /*
12364 * QUESTION TODO: What does the "first" and "last" stuff do?
12365 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012366 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012367 if (*first == cur)
12368 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012369 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012370#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012371 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012372#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012373 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012374#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012375 {
12376 break;
12377 }
12378 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012379 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012380 if (*last == cur)
12381 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012382 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012383#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012384 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012385#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012386 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012387#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012388 {
12389 break;
12390 }
12391 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012392
12393 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012394
Daniel Veillardf06307e2001-07-03 10:35:50 +000012395#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012396 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12397#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012398
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012399 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012400 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012401 total = 0;
12402 STRANGE
12403 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012404 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012405 if (type == NODE_TYPE_NODE) {
12406 switch (cur->type) {
12407 case XML_DOCUMENT_NODE:
12408 case XML_HTML_DOCUMENT_NODE:
12409#ifdef LIBXML_DOCB_ENABLED
12410 case XML_DOCB_DOCUMENT_NODE:
12411#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012412 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012413 case XML_ATTRIBUTE_NODE:
12414 case XML_PI_NODE:
12415 case XML_COMMENT_NODE:
12416 case XML_CDATA_SECTION_NODE:
12417 case XML_TEXT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012418 XP_TEST_HIT
12419 break;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012420 case XML_NAMESPACE_DECL: {
12421 if (axis == AXIS_NAMESPACE) {
12422 XP_TEST_HIT_NS
12423 } else {
Nick Wellnhofer6eb08942016-05-05 16:49:00 +020012424 hasNsNodes = 1;
Nick Wellnhoferf39fd662016-04-27 03:01:16 +020012425 XP_TEST_HIT
12426 }
12427 break;
12428 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012429 default:
12430 break;
12431 }
12432 } else if (cur->type == type) {
Daniel Veillard713434d2012-09-26 10:21:06 +080012433 if (cur->type == XML_NAMESPACE_DECL)
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012434 XP_TEST_HIT_NS
12435 else
12436 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012437 } else if ((type == NODE_TYPE_TEXT) &&
12438 (cur->type == XML_CDATA_SECTION_NODE))
12439 {
12440 XP_TEST_HIT
12441 }
12442 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012443 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012444 if ((cur->type == XML_PI_NODE) &&
12445 ((name == NULL) || xmlStrEqual(name, cur->name)))
12446 {
12447 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012448 }
12449 break;
12450 case NODE_TEST_ALL:
12451 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012452 if (cur->type == XML_ATTRIBUTE_NODE)
12453 {
Nick Wellnhofere8de99f2013-08-05 01:26:25 +020012454 if (prefix == NULL)
12455 {
12456 XP_TEST_HIT
12457 } else if ((cur->ns != NULL) &&
12458 (xmlStrEqual(URI, cur->ns->href)))
12459 {
12460 XP_TEST_HIT
12461 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012462 }
12463 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012464 if (cur->type == XML_NAMESPACE_DECL)
12465 {
12466 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012467 }
12468 } else {
12469 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012470 if (prefix == NULL)
12471 {
12472 XP_TEST_HIT
12473
Daniel Veillardf06307e2001-07-03 10:35:50 +000012474 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012475 (xmlStrEqual(URI, cur->ns->href)))
12476 {
12477 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012478 }
12479 }
12480 }
12481 break;
12482 case NODE_TEST_NS:{
12483 TODO;
12484 break;
12485 }
12486 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012487 if (axis == AXIS_ATTRIBUTE) {
12488 if (cur->type != XML_ATTRIBUTE_NODE)
12489 break;
12490 } else if (axis == AXIS_NAMESPACE) {
12491 if (cur->type != XML_NAMESPACE_DECL)
12492 break;
12493 } else {
12494 if (cur->type != XML_ELEMENT_NODE)
12495 break;
12496 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012497 switch (cur->type) {
12498 case XML_ELEMENT_NODE:
12499 if (xmlStrEqual(name, cur->name)) {
12500 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012501 if (cur->ns == NULL)
12502 {
12503 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012504 }
12505 } else {
12506 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012507 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012508 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012509 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012510 }
12511 }
12512 }
12513 break;
12514 case XML_ATTRIBUTE_NODE:{
12515 xmlAttrPtr attr = (xmlAttrPtr) cur;
12516
12517 if (xmlStrEqual(name, attr->name)) {
12518 if (prefix == NULL) {
12519 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012520 (attr->ns->prefix == NULL))
12521 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012522 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012523 }
12524 } else {
12525 if ((attr->ns != NULL) &&
12526 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012527 attr->ns->href)))
12528 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012529 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012530 }
12531 }
12532 }
12533 break;
12534 }
12535 case XML_NAMESPACE_DECL:
12536 if (cur->type == XML_NAMESPACE_DECL) {
12537 xmlNsPtr ns = (xmlNsPtr) cur;
12538
12539 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012540 && (xmlStrEqual(ns->prefix, name)))
12541 {
12542 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012543 }
12544 }
12545 break;
12546 default:
12547 break;
12548 }
12549 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012550 } /* switch(test) */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012551 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012552
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012553 goto apply_predicates;
12554
Daniel Veillard45490ae2008-07-29 09:13:19 +000012555axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012556 /*
12557 * We have a "/foo[n]", and position() = n was reached.
12558 * Note that we can have as well "/foo/::parent::foo[1]", so
12559 * a duplicate-aware merge is still needed.
12560 * Merge with the result.
12561 */
12562 if (outSeq == NULL) {
12563 outSeq = seq;
12564 seq = NULL;
12565 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012566 outSeq = mergeAndClear(outSeq, seq, 0);
12567 /*
12568 * Break if only a true/false result was requested.
12569 */
12570 if (toBool)
12571 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012572 continue;
12573
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012574first_hit: /* ---------------------------------------------------------- */
12575 /*
12576 * Break if only a true/false result was requested and
12577 * no predicates existed and a node test succeeded.
12578 */
12579 if (outSeq == NULL) {
12580 outSeq = seq;
12581 seq = NULL;
12582 } else
12583 outSeq = mergeAndClear(outSeq, seq, 0);
12584 break;
12585
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012586#ifdef DEBUG_STEP
12587 if (seq != NULL)
12588 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012589#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012590
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012591apply_predicates: /* --------------------------------------------------- */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012592 if (ctxt->error != XPATH_EXPRESSION_OK)
12593 goto error;
12594
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012595 /*
12596 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012597 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012598 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12599 /*
12600 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012601 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012602 /*
12603 * QUESTION TODO: The old predicate evaluation took into
12604 * account location-sets.
12605 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12606 * Do we expect such a set here?
12607 * All what I learned now from the evaluation semantics
12608 * does not indicate that a location-set will be processed
12609 * here, so this looks OK.
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012610 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012611 /*
12612 * Iterate over all predicates, starting with the outermost
12613 * predicate.
12614 * TODO: Problem: we cannot execute the inner predicates first
12615 * since we cannot go back *up* the operator tree!
12616 * Options we have:
12617 * 1) Use of recursive functions (like is it currently done
12618 * via xmlXPathCompOpEval())
12619 * 2) Add a predicate evaluation information stack to the
12620 * context struct
12621 * 3) Change the way the operators are linked; we need a
12622 * "parent" field on xmlXPathStepOp
12623 *
12624 * For the moment, I'll try to solve this with a recursive
12625 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012626 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012627 size = seq->nodeNr;
12628 if (hasPredicateRange != 0)
12629 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12630 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12631 else
12632 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12633 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012634
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012635 if (ctxt->error != XPATH_EXPRESSION_OK) {
12636 total = 0;
12637 goto error;
12638 }
12639 /*
12640 * Add the filtered set of nodes to the result node set.
12641 */
12642 if (newSize == 0) {
12643 /*
12644 * The predicates filtered all nodes out.
12645 */
12646 xmlXPathNodeSetClear(seq, hasNsNodes);
12647 } else if (seq->nodeNr > 0) {
12648 /*
12649 * Add to result set.
12650 */
12651 if (outSeq == NULL) {
12652 if (size != newSize) {
12653 /*
12654 * We need to merge and clear here, since
12655 * the sequence will contained NULLed entries.
12656 */
12657 outSeq = mergeAndClear(NULL, seq, 1);
12658 } else {
12659 outSeq = seq;
12660 seq = NULL;
12661 }
12662 } else
12663 outSeq = mergeAndClear(outSeq, seq,
12664 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012665 /*
12666 * Break if only a true/false result was requested.
12667 */
12668 if (toBool)
12669 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012670 }
12671 } else if (seq->nodeNr > 0) {
12672 /*
12673 * Add to result set.
12674 */
12675 if (outSeq == NULL) {
12676 outSeq = seq;
12677 seq = NULL;
12678 } else {
12679 outSeq = mergeAndClear(outSeq, seq, 0);
12680 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012681 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012682 }
12683
12684error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012685 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012686 /*
12687 * QUESTION TODO: What does this do and why?
12688 * TODO: Do we have to do this also for the "error"
12689 * cleanup further down?
12690 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012691 ctxt->value->boolval = 1;
12692 ctxt->value->user = obj->user;
12693 obj->user = NULL;
12694 obj->boolval = 0;
12695 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012696 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012697
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012698 /*
12699 * Ensure we return at least an emtpy set.
12700 */
12701 if (outSeq == NULL) {
12702 if ((seq != NULL) && (seq->nodeNr == 0))
12703 outSeq = seq;
12704 else
12705 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012706 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012707 }
12708 if ((seq != NULL) && (seq != outSeq)) {
12709 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012710 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012711 /*
12712 * Hand over the result. Better to push the set also in
12713 * case of errors.
12714 */
12715 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12716 /*
12717 * Reset the context node.
12718 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012719 xpctxt->node = oldContextNode;
Nick Wellnhofer82b73032016-04-30 17:53:10 +020012720 /*
12721 * When traversing the namespace axis in "toBool" mode, it's
12722 * possible that tmpNsList wasn't freed.
12723 */
12724 if (xpctxt->tmpNsList != NULL) {
12725 xmlFree(xpctxt->tmpNsList);
12726 xpctxt->tmpNsList = NULL;
12727 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012728
12729#ifdef DEBUG_STEP
12730 xmlGenericError(xmlGenericErrorContext,
12731 "\nExamined %d nodes, found %d nodes at that step\n",
12732 total, nbMatches);
12733#endif
12734
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012735 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012736}
12737
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012738static int
12739xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12740 xmlXPathStepOpPtr op, xmlNodePtr * first);
12741
Daniel Veillardf06307e2001-07-03 10:35:50 +000012742/**
12743 * xmlXPathCompOpEvalFirst:
12744 * @ctxt: the XPath parser context with the compiled expression
12745 * @op: an XPath compiled operation
12746 * @first: the first elem found so far
12747 *
12748 * Evaluate the Precompiled XPath operation searching only the first
12749 * element in document order
12750 *
12751 * Returns the number of examined objects.
12752 */
12753static int
12754xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12755 xmlXPathStepOpPtr op, xmlNodePtr * first)
12756{
12757 int total = 0, cur;
12758 xmlXPathCompExprPtr comp;
12759 xmlXPathObjectPtr arg1, arg2;
12760
Daniel Veillard556c6682001-10-06 09:59:51 +000012761 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012762 comp = ctxt->comp;
12763 switch (op->op) {
12764 case XPATH_OP_END:
12765 return (0);
12766 case XPATH_OP_UNION:
12767 total =
12768 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12769 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012770 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012771 if ((ctxt->value != NULL)
12772 && (ctxt->value->type == XPATH_NODESET)
12773 && (ctxt->value->nodesetval != NULL)
12774 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12775 /*
12776 * limit tree traversing to first node in the result
12777 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012778 /*
12779 * OPTIMIZE TODO: This implicitely sorts
12780 * the result, even if not needed. E.g. if the argument
12781 * of the count() function, no sorting is needed.
12782 * OPTIMIZE TODO: How do we know if the node-list wasn't
12783 * aready sorted?
12784 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012785 if (ctxt->value->nodesetval->nodeNr > 1)
12786 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012787 *first = ctxt->value->nodesetval->nodeTab[0];
12788 }
12789 cur =
12790 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12791 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012792 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012793
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012794 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012795 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012796 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12797 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12798 xmlXPathReleaseObject(ctxt->context, arg1);
12799 xmlXPathReleaseObject(ctxt->context, arg2);
12800 XP_ERROR0(XPATH_INVALID_TYPE);
12801 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012802
12803 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12804 arg2->nodesetval);
12805 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012806 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012807 /* optimizer */
12808 if (total > cur)
12809 xmlXPathCompSwap(op);
12810 return (total + cur);
12811 case XPATH_OP_ROOT:
12812 xmlXPathRoot(ctxt);
12813 return (0);
12814 case XPATH_OP_NODE:
12815 if (op->ch1 != -1)
12816 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012817 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012818 if (op->ch2 != -1)
12819 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012820 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012821 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12822 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012823 return (total);
12824 case XPATH_OP_RESET:
12825 if (op->ch1 != -1)
12826 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012827 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012828 if (op->ch2 != -1)
12829 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012830 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012831 ctxt->context->node = NULL;
12832 return (total);
12833 case XPATH_OP_COLLECT:{
12834 if (op->ch1 == -1)
12835 return (total);
12836
12837 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012838 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012839
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012840 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012841 return (total);
12842 }
12843 case XPATH_OP_VALUE:
12844 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012845 xmlXPathCacheObjectCopy(ctxt->context,
12846 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012847 return (0);
12848 case XPATH_OP_SORT:
12849 if (op->ch1 != -1)
12850 total +=
12851 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12852 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012853 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012854 if ((ctxt->value != NULL)
12855 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012856 && (ctxt->value->nodesetval != NULL)
12857 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012858 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12859 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012860#ifdef XP_OPTIMIZED_FILTER_FIRST
12861 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012862 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012863 return (total);
12864#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012865 default:
12866 return (xmlXPathCompOpEval(ctxt, op));
12867 }
12868}
12869
12870/**
12871 * xmlXPathCompOpEvalLast:
12872 * @ctxt: the XPath parser context with the compiled expression
12873 * @op: an XPath compiled operation
12874 * @last: the last elem found so far
12875 *
12876 * Evaluate the Precompiled XPath operation searching only the last
12877 * element in document order
12878 *
William M. Brack08171912003-12-29 02:52:11 +000012879 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012880 */
12881static int
12882xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12883 xmlNodePtr * last)
12884{
12885 int total = 0, cur;
12886 xmlXPathCompExprPtr comp;
12887 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012888 xmlNodePtr bak;
12889 xmlDocPtr bakd;
12890 int pp;
12891 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012892
Daniel Veillard556c6682001-10-06 09:59:51 +000012893 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012894 comp = ctxt->comp;
12895 switch (op->op) {
12896 case XPATH_OP_END:
12897 return (0);
12898 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012899 bakd = ctxt->context->doc;
12900 bak = ctxt->context->node;
12901 pp = ctxt->context->proximityPosition;
12902 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012903 total =
12904 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012905 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012906 if ((ctxt->value != NULL)
12907 && (ctxt->value->type == XPATH_NODESET)
12908 && (ctxt->value->nodesetval != NULL)
12909 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12910 /*
12911 * limit tree traversing to first node in the result
12912 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012913 if (ctxt->value->nodesetval->nodeNr > 1)
12914 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012915 *last =
12916 ctxt->value->nodesetval->nodeTab[ctxt->value->
12917 nodesetval->nodeNr -
12918 1];
12919 }
William M. Brackce4fc562004-01-22 02:47:18 +000012920 ctxt->context->doc = bakd;
12921 ctxt->context->node = bak;
12922 ctxt->context->proximityPosition = pp;
12923 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012924 cur =
12925 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012926 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012927 if ((ctxt->value != NULL)
12928 && (ctxt->value->type == XPATH_NODESET)
12929 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012930 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012931 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012932
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012933 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012934 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020012935 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12936 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12937 xmlXPathReleaseObject(ctxt->context, arg1);
12938 xmlXPathReleaseObject(ctxt->context, arg2);
12939 XP_ERROR0(XPATH_INVALID_TYPE);
12940 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012941
12942 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12943 arg2->nodesetval);
12944 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012945 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012946 /* optimizer */
12947 if (total > cur)
12948 xmlXPathCompSwap(op);
12949 return (total + cur);
12950 case XPATH_OP_ROOT:
12951 xmlXPathRoot(ctxt);
12952 return (0);
12953 case XPATH_OP_NODE:
12954 if (op->ch1 != -1)
12955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012956 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012957 if (op->ch2 != -1)
12958 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012959 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012960 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12961 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012962 return (total);
12963 case XPATH_OP_RESET:
12964 if (op->ch1 != -1)
12965 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012966 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012967 if (op->ch2 != -1)
12968 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012969 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012970 ctxt->context->node = NULL;
12971 return (total);
12972 case XPATH_OP_COLLECT:{
12973 if (op->ch1 == -1)
12974 return (0);
12975
12976 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012977 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012978
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012979 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012980 return (total);
12981 }
12982 case XPATH_OP_VALUE:
12983 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012984 xmlXPathCacheObjectCopy(ctxt->context,
12985 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012986 return (0);
12987 case XPATH_OP_SORT:
12988 if (op->ch1 != -1)
12989 total +=
12990 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12991 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012992 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012993 if ((ctxt->value != NULL)
12994 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012995 && (ctxt->value->nodesetval != NULL)
12996 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012997 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12998 return (total);
12999 default:
13000 return (xmlXPathCompOpEval(ctxt, op));
13001 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013002}
13003
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013004#ifdef XP_OPTIMIZED_FILTER_FIRST
13005static int
13006xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
13007 xmlXPathStepOpPtr op, xmlNodePtr * first)
13008{
13009 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013010 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013011 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013012 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013013 xmlNodeSetPtr oldset;
13014 xmlNodePtr oldnode;
13015 xmlDocPtr oldDoc;
13016 int i;
13017
13018 CHECK_ERROR0;
13019 comp = ctxt->comp;
13020 /*
13021 * Optimization for ()[last()] selection i.e. the last elem
13022 */
13023 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13024 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13025 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13026 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013027
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013028 if ((f != -1) &&
13029 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13030 (comp->steps[f].value5 == NULL) &&
13031 (comp->steps[f].value == 0) &&
13032 (comp->steps[f].value4 != NULL) &&
13033 (xmlStrEqual
13034 (comp->steps[f].value4, BAD_CAST "last"))) {
13035 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013036
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013037 total +=
13038 xmlXPathCompOpEvalLast(ctxt,
13039 &comp->steps[op->ch1],
13040 &last);
13041 CHECK_ERROR0;
13042 /*
13043 * The nodeset should be in document order,
13044 * Keep only the last value
13045 */
13046 if ((ctxt->value != NULL) &&
13047 (ctxt->value->type == XPATH_NODESET) &&
13048 (ctxt->value->nodesetval != NULL) &&
13049 (ctxt->value->nodesetval->nodeTab != NULL) &&
13050 (ctxt->value->nodesetval->nodeNr > 1)) {
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013051 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013052 *first = *(ctxt->value->nodesetval->nodeTab);
13053 }
13054 return (total);
13055 }
13056 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013057
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013058 if (op->ch1 != -1)
13059 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13060 CHECK_ERROR0;
13061 if (op->ch2 == -1)
13062 return (total);
13063 if (ctxt->value == NULL)
13064 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013065
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013066#ifdef LIBXML_XPTR_ENABLED
13067 oldnode = ctxt->context->node;
13068 /*
13069 * Hum are we filtering the result of an XPointer expression
13070 */
13071 if (ctxt->value->type == XPATH_LOCATIONSET) {
13072 xmlXPathObjectPtr tmp = NULL;
13073 xmlLocationSetPtr newlocset = NULL;
13074 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013075
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013076 /*
13077 * Extract the old locset, and then evaluate the result of the
13078 * expression for all the element in the locset. use it to grow
13079 * up a new locset.
13080 */
13081 CHECK_TYPE0(XPATH_LOCATIONSET);
13082 obj = valuePop(ctxt);
13083 oldlocset = obj->user;
13084 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013085
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013086 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13087 ctxt->context->contextSize = 0;
13088 ctxt->context->proximityPosition = 0;
13089 if (op->ch2 != -1)
13090 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13091 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013092 if (res != NULL) {
13093 xmlXPathReleaseObject(ctxt->context, res);
13094 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013095 valuePush(ctxt, obj);
13096 CHECK_ERROR0;
13097 return (total);
13098 }
13099 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013100
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013101 for (i = 0; i < oldlocset->locNr; i++) {
13102 /*
13103 * Run the evaluation with a node list made of a
13104 * single item in the nodelocset.
13105 */
13106 ctxt->context->node = oldlocset->locTab[i]->user;
13107 ctxt->context->contextSize = oldlocset->locNr;
13108 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013109 if (tmp == NULL) {
13110 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13111 ctxt->context->node);
13112 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013113 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13114 ctxt->context->node) < 0) {
13115 ctxt->error = XPATH_MEMORY_ERROR;
13116 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013117 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013118 valuePush(ctxt, tmp);
13119 if (op->ch2 != -1)
13120 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13121 if (ctxt->error != XPATH_EXPRESSION_OK) {
13122 xmlXPathFreeObject(obj);
13123 return(0);
13124 }
13125 /*
13126 * The result of the evaluation need to be tested to
13127 * decided whether the filter succeeded or not
13128 */
13129 res = valuePop(ctxt);
13130 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13131 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013132 xmlXPathCacheObjectCopy(ctxt->context,
13133 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013134 }
13135 /*
13136 * Cleanup
13137 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013138 if (res != NULL) {
13139 xmlXPathReleaseObject(ctxt->context, res);
13140 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013141 if (ctxt->value == tmp) {
13142 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013143 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013144 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013145 * REVISIT TODO: Don't create a temporary nodeset
13146 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013147 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013148 /* OLD: xmlXPathFreeObject(res); */
13149 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013150 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013151 ctxt->context->node = NULL;
13152 /*
13153 * Only put the first node in the result, then leave.
13154 */
13155 if (newlocset->locNr > 0) {
13156 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13157 break;
13158 }
13159 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013160 if (tmp != NULL) {
13161 xmlXPathReleaseObject(ctxt->context, tmp);
13162 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013163 /*
13164 * The result is used as the new evaluation locset.
13165 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013166 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013167 ctxt->context->node = NULL;
13168 ctxt->context->contextSize = -1;
13169 ctxt->context->proximityPosition = -1;
13170 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13171 ctxt->context->node = oldnode;
13172 return (total);
13173 }
13174#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013175
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013176 /*
13177 * Extract the old set, and then evaluate the result of the
13178 * expression for all the element in the set. use it to grow
13179 * up a new set.
13180 */
13181 CHECK_TYPE0(XPATH_NODESET);
13182 obj = valuePop(ctxt);
13183 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013184
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013185 oldnode = ctxt->context->node;
13186 oldDoc = ctxt->context->doc;
13187 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013188
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013189 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13190 ctxt->context->contextSize = 0;
13191 ctxt->context->proximityPosition = 0;
13192 /* QUESTION TODO: Why was this code commented out?
13193 if (op->ch2 != -1)
13194 total +=
13195 xmlXPathCompOpEval(ctxt,
13196 &comp->steps[op->ch2]);
13197 CHECK_ERROR0;
13198 res = valuePop(ctxt);
13199 if (res != NULL)
13200 xmlXPathFreeObject(res);
13201 */
13202 valuePush(ctxt, obj);
13203 ctxt->context->node = oldnode;
13204 CHECK_ERROR0;
13205 } else {
13206 xmlNodeSetPtr newset;
13207 xmlXPathObjectPtr tmp = NULL;
13208 /*
13209 * Initialize the new set.
13210 * Also set the xpath document in case things like
13211 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013212 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013213 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013214 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013215
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013216 for (i = 0; i < oldset->nodeNr; i++) {
13217 /*
13218 * Run the evaluation with a node list made of
13219 * a single item in the nodeset.
13220 */
13221 ctxt->context->node = oldset->nodeTab[i];
13222 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13223 (oldset->nodeTab[i]->doc != NULL))
13224 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013225 if (tmp == NULL) {
13226 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13227 ctxt->context->node);
13228 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013229 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13230 ctxt->context->node) < 0) {
13231 ctxt->error = XPATH_MEMORY_ERROR;
13232 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013233 }
13234 valuePush(ctxt, tmp);
13235 ctxt->context->contextSize = oldset->nodeNr;
13236 ctxt->context->proximityPosition = i + 1;
13237 if (op->ch2 != -1)
13238 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13239 if (ctxt->error != XPATH_EXPRESSION_OK) {
13240 xmlXPathFreeNodeSet(newset);
13241 xmlXPathFreeObject(obj);
13242 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013243 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013244 /*
13245 * The result of the evaluation needs to be tested to
13246 * decide whether the filter succeeded or not
13247 */
13248 res = valuePop(ctxt);
13249 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013250 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13251 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013252 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013253 /*
13254 * Cleanup
13255 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013256 if (res != NULL) {
13257 xmlXPathReleaseObject(ctxt->context, res);
13258 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013259 if (ctxt->value == tmp) {
13260 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013261 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013262 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013263 * in order to avoid massive recreation inside this
13264 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013265 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013266 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013267 } else
13268 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013269 ctxt->context->node = NULL;
13270 /*
13271 * Only put the first node in the result, then leave.
13272 */
13273 if (newset->nodeNr > 0) {
13274 *first = *(newset->nodeTab);
13275 break;
13276 }
13277 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013278 if (tmp != NULL) {
13279 xmlXPathReleaseObject(ctxt->context, tmp);
13280 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013281 /*
13282 * The result is used as the new evaluation set.
13283 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013284 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013285 ctxt->context->node = NULL;
13286 ctxt->context->contextSize = -1;
13287 ctxt->context->proximityPosition = -1;
13288 /* may want to move this past the '}' later */
13289 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013290 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013291 }
13292 ctxt->context->node = oldnode;
13293 return(total);
13294}
13295#endif /* XP_OPTIMIZED_FILTER_FIRST */
13296
Owen Taylor3473f882001-02-23 17:55:21 +000013297/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013298 * xmlXPathCompOpEval:
13299 * @ctxt: the XPath parser context with the compiled expression
13300 * @op: an XPath compiled operation
13301 *
13302 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013303 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013304 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013305static int
13306xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13307{
13308 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013309 int equal, ret;
13310 xmlXPathCompExprPtr comp;
13311 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013312 xmlNodePtr bak;
13313 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013314 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013315 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013316
Daniel Veillard556c6682001-10-06 09:59:51 +000013317 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013318 comp = ctxt->comp;
13319 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013320 case XPATH_OP_END:
13321 return (0);
13322 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013323 bakd = ctxt->context->doc;
13324 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013325 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013326 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013327 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013328 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013329 xmlXPathBooleanFunction(ctxt, 1);
13330 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13331 return (total);
13332 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013333 ctxt->context->doc = bakd;
13334 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013335 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013336 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013337 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013338 if (ctxt->error) {
13339 xmlXPathFreeObject(arg2);
13340 return(0);
13341 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013342 xmlXPathBooleanFunction(ctxt, 1);
13343 arg1 = valuePop(ctxt);
13344 arg1->boolval &= arg2->boolval;
13345 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013346 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013347 return (total);
13348 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013349 bakd = ctxt->context->doc;
13350 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013351 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013352 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013353 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013354 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013355 xmlXPathBooleanFunction(ctxt, 1);
13356 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13357 return (total);
13358 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013359 ctxt->context->doc = bakd;
13360 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013361 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013362 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013363 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013364 if (ctxt->error) {
13365 xmlXPathFreeObject(arg2);
13366 return(0);
13367 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013368 xmlXPathBooleanFunction(ctxt, 1);
13369 arg1 = valuePop(ctxt);
13370 arg1->boolval |= arg2->boolval;
13371 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013372 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013373 return (total);
13374 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013375 bakd = ctxt->context->doc;
13376 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013377 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013378 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013379 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013380 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013381 ctxt->context->doc = bakd;
13382 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013383 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013384 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013385 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013386 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013387 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013388 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013389 else
13390 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013391 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013392 return (total);
13393 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013394 bakd = ctxt->context->doc;
13395 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013396 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013397 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013398 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013399 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013400 ctxt->context->doc = bakd;
13401 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013402 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013403 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013404 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013405 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013406 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013407 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013408 return (total);
13409 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013410 bakd = ctxt->context->doc;
13411 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013412 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013413 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013414 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013415 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013416 if (op->ch2 != -1) {
13417 ctxt->context->doc = bakd;
13418 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013419 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013420 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013421 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013422 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013423 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013424 if (op->value == 0)
13425 xmlXPathSubValues(ctxt);
13426 else if (op->value == 1)
13427 xmlXPathAddValues(ctxt);
13428 else if (op->value == 2)
13429 xmlXPathValueFlipSign(ctxt);
13430 else if (op->value == 3) {
13431 CAST_TO_NUMBER;
13432 CHECK_TYPE0(XPATH_NUMBER);
13433 }
13434 return (total);
13435 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013436 bakd = ctxt->context->doc;
13437 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013438 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013439 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013440 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013441 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013442 ctxt->context->doc = bakd;
13443 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013444 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013445 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013446 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013447 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013448 if (op->value == 0)
13449 xmlXPathMultValues(ctxt);
13450 else if (op->value == 1)
13451 xmlXPathDivValues(ctxt);
13452 else if (op->value == 2)
13453 xmlXPathModValues(ctxt);
13454 return (total);
13455 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013456 bakd = ctxt->context->doc;
13457 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013458 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013459 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013460 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013461 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013462 ctxt->context->doc = bakd;
13463 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013464 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013465 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013466 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013467 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013468
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013469 arg2 = valuePop(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013470 arg1 = valuePop(ctxt);
Nick Wellnhoferd42a7062017-05-27 14:58:19 +020013471 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13472 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13473 xmlXPathReleaseObject(ctxt->context, arg1);
13474 xmlXPathReleaseObject(ctxt->context, arg2);
13475 XP_ERROR0(XPATH_INVALID_TYPE);
13476 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013477
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013478 if ((arg1->nodesetval == NULL) ||
13479 ((arg2->nodesetval != NULL) &&
13480 (arg2->nodesetval->nodeNr != 0)))
13481 {
13482 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13483 arg2->nodesetval);
13484 }
13485
Daniel Veillardf06307e2001-07-03 10:35:50 +000013486 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013487 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013488 return (total);
13489 case XPATH_OP_ROOT:
13490 xmlXPathRoot(ctxt);
13491 return (total);
13492 case XPATH_OP_NODE:
13493 if (op->ch1 != -1)
13494 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013495 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013496 if (op->ch2 != -1)
13497 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013498 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013499 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13500 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013501 return (total);
13502 case XPATH_OP_RESET:
13503 if (op->ch1 != -1)
13504 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013505 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013506 if (op->ch2 != -1)
13507 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013508 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013509 ctxt->context->node = NULL;
13510 return (total);
13511 case XPATH_OP_COLLECT:{
13512 if (op->ch1 == -1)
13513 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013514
Daniel Veillardf06307e2001-07-03 10:35:50 +000013515 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013516 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013517
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013518 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013519 return (total);
13520 }
13521 case XPATH_OP_VALUE:
13522 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013523 xmlXPathCacheObjectCopy(ctxt->context,
13524 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013525 return (total);
13526 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013527 xmlXPathObjectPtr val;
13528
Daniel Veillardf06307e2001-07-03 10:35:50 +000013529 if (op->ch1 != -1)
13530 total +=
13531 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013532 if (op->value5 == NULL) {
13533 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13534 if (val == NULL) {
13535 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13536 return(0);
13537 }
13538 valuePush(ctxt, val);
13539 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013540 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013541
Daniel Veillardf06307e2001-07-03 10:35:50 +000013542 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13543 if (URI == NULL) {
13544 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013545 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13546 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013547 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013548 return (total);
13549 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013550 val = xmlXPathVariableLookupNS(ctxt->context,
13551 op->value4, URI);
13552 if (val == NULL) {
13553 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13554 return(0);
13555 }
13556 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013557 }
13558 return (total);
13559 }
13560 case XPATH_OP_FUNCTION:{
13561 xmlXPathFunction func;
13562 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013563 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013564 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013565
Daniel Veillardf5048b32011-08-18 17:10:13 +080013566 frame = xmlXPathSetFrame(ctxt);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013567 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013568 total +=
13569 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013570 if (ctxt->error != XPATH_EXPRESSION_OK) {
13571 xmlXPathPopFrame(ctxt, frame);
13572 return (total);
13573 }
13574 }
13575 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013576 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013577 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013578 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013579 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013580 return (total);
13581 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013582 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013583 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13584 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013585 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013586 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013587 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013588 return (total);
13589 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013590 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013591 if (op->cache != NULL)
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013592 func = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013593 else {
13594 const xmlChar *URI = NULL;
13595
13596 if (op->value5 == NULL)
13597 func =
13598 xmlXPathFunctionLookup(ctxt->context,
13599 op->value4);
13600 else {
13601 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13602 if (URI == NULL) {
13603 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013604 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13605 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013606 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013607 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013608 return (total);
13609 }
13610 func = xmlXPathFunctionLookupNS(ctxt->context,
13611 op->value4, URI);
13612 }
13613 if (func == NULL) {
13614 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013615 "xmlXPathCompOpEval: function %s not found\n",
13616 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013617 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013618 }
Nick Wellnhofer229d1f92016-08-22 13:21:57 +020013619 op->cache = func;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013620 op->cacheURI = (void *) URI;
13621 }
13622 oldFunc = ctxt->context->function;
13623 oldFuncURI = ctxt->context->functionURI;
13624 ctxt->context->function = op->value4;
13625 ctxt->context->functionURI = op->cacheURI;
13626 func(ctxt, op->value);
13627 ctxt->context->function = oldFunc;
13628 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013629 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013630 return (total);
13631 }
13632 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013633 bakd = ctxt->context->doc;
13634 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013635 pp = ctxt->context->proximityPosition;
13636 cs = ctxt->context->contextSize;
Nick Wellnhofer07def302014-03-21 19:38:08 +010013637 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013638 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013639 ctxt->context->contextSize = cs;
13640 ctxt->context->proximityPosition = pp;
13641 ctxt->context->node = bak;
13642 ctxt->context->doc = bakd;
13643 CHECK_ERROR0;
13644 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013645 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013646 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013647 ctxt->context->contextSize = cs;
13648 ctxt->context->proximityPosition = pp;
13649 ctxt->context->node = bak;
13650 ctxt->context->doc = bakd;
William M. Brack72ee48d2003-12-30 08:30:19 +000013651 CHECK_ERROR0;
13652 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013653 return (total);
13654 case XPATH_OP_PREDICATE:
13655 case XPATH_OP_FILTER:{
13656 xmlXPathObjectPtr res;
13657 xmlXPathObjectPtr obj, tmp;
13658 xmlNodeSetPtr newset = NULL;
13659 xmlNodeSetPtr oldset;
13660 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013661 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013662 int i;
13663
13664 /*
13665 * Optimization for ()[1] selection i.e. the first elem
13666 */
13667 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013668#ifdef XP_OPTIMIZED_FILTER_FIRST
13669 /*
13670 * FILTER TODO: Can we assume that the inner processing
13671 * will result in an ordered list if we have an
13672 * XPATH_OP_FILTER?
13673 * What about an additional field or flag on
13674 * xmlXPathObject like @sorted ? This way we wouln'd need
13675 * to assume anything, so it would be more robust and
13676 * easier to optimize.
13677 */
13678 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13679 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13680#else
13681 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13682#endif
13683 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013684 xmlXPathObjectPtr val;
13685
13686 val = comp->steps[op->ch2].value4;
13687 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13688 (val->floatval == 1.0)) {
13689 xmlNodePtr first = NULL;
13690
13691 total +=
13692 xmlXPathCompOpEvalFirst(ctxt,
13693 &comp->steps[op->ch1],
13694 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013695 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013696 /*
13697 * The nodeset should be in document order,
13698 * Keep only the first value
13699 */
13700 if ((ctxt->value != NULL) &&
13701 (ctxt->value->type == XPATH_NODESET) &&
13702 (ctxt->value->nodesetval != NULL) &&
13703 (ctxt->value->nodesetval->nodeNr > 1))
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013704 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13705 1, 1);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013706 return (total);
13707 }
13708 }
13709 /*
13710 * Optimization for ()[last()] selection i.e. the last elem
13711 */
13712 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13713 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13714 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13715 int f = comp->steps[op->ch2].ch1;
13716
13717 if ((f != -1) &&
13718 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13719 (comp->steps[f].value5 == NULL) &&
13720 (comp->steps[f].value == 0) &&
13721 (comp->steps[f].value4 != NULL) &&
13722 (xmlStrEqual
13723 (comp->steps[f].value4, BAD_CAST "last"))) {
13724 xmlNodePtr last = NULL;
13725
13726 total +=
13727 xmlXPathCompOpEvalLast(ctxt,
13728 &comp->steps[op->ch1],
13729 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013730 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013731 /*
13732 * The nodeset should be in document order,
13733 * Keep only the last value
13734 */
13735 if ((ctxt->value != NULL) &&
13736 (ctxt->value->type == XPATH_NODESET) &&
13737 (ctxt->value->nodesetval != NULL) &&
13738 (ctxt->value->nodesetval->nodeTab != NULL) &&
Nick Wellnhofer95a92492017-05-21 15:18:58 +020013739 (ctxt->value->nodesetval->nodeNr > 1))
13740 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013741 return (total);
13742 }
13743 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013744 /*
13745 * Process inner predicates first.
13746 * Example "index[parent::book][1]":
13747 * ...
13748 * PREDICATE <-- we are here "[1]"
13749 * PREDICATE <-- process "[parent::book]" first
13750 * SORT
13751 * COLLECT 'parent' 'name' 'node' book
13752 * NODE
13753 * ELEM Object is a number : 1
13754 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013755 if (op->ch1 != -1)
13756 total +=
13757 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013758 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013759 if (op->ch2 == -1)
13760 return (total);
13761 if (ctxt->value == NULL)
13762 return (total);
13763
13764 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013765
13766#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013767 /*
13768 * Hum are we filtering the result of an XPointer expression
13769 */
13770 if (ctxt->value->type == XPATH_LOCATIONSET) {
13771 xmlLocationSetPtr newlocset = NULL;
13772 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013773
Daniel Veillardf06307e2001-07-03 10:35:50 +000013774 /*
13775 * Extract the old locset, and then evaluate the result of the
13776 * expression for all the element in the locset. use it to grow
13777 * up a new locset.
13778 */
13779 CHECK_TYPE0(XPATH_LOCATIONSET);
13780 obj = valuePop(ctxt);
13781 oldlocset = obj->user;
13782 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013783
Daniel Veillardf06307e2001-07-03 10:35:50 +000013784 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13785 ctxt->context->contextSize = 0;
13786 ctxt->context->proximityPosition = 0;
13787 if (op->ch2 != -1)
13788 total +=
13789 xmlXPathCompOpEval(ctxt,
13790 &comp->steps[op->ch2]);
13791 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013792 if (res != NULL) {
13793 xmlXPathReleaseObject(ctxt->context, res);
13794 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013795 valuePush(ctxt, obj);
13796 CHECK_ERROR0;
13797 return (total);
13798 }
13799 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013800
Daniel Veillardf06307e2001-07-03 10:35:50 +000013801 for (i = 0; i < oldlocset->locNr; i++) {
13802 /*
13803 * Run the evaluation with a node list made of a
13804 * single item in the nodelocset.
13805 */
13806 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013807 ctxt->context->contextSize = oldlocset->locNr;
13808 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013809 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13810 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013811 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013812
Daniel Veillardf06307e2001-07-03 10:35:50 +000013813 if (op->ch2 != -1)
13814 total +=
13815 xmlXPathCompOpEval(ctxt,
13816 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013817 if (ctxt->error != XPATH_EXPRESSION_OK) {
13818 xmlXPathFreeObject(obj);
13819 return(0);
13820 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013821
Daniel Veillardf06307e2001-07-03 10:35:50 +000013822 /*
13823 * The result of the evaluation need to be tested to
13824 * decided whether the filter succeeded or not
13825 */
13826 res = valuePop(ctxt);
13827 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13828 xmlXPtrLocationSetAdd(newlocset,
13829 xmlXPathObjectCopy
13830 (oldlocset->locTab[i]));
13831 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013832
Daniel Veillardf06307e2001-07-03 10:35:50 +000013833 /*
13834 * Cleanup
13835 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013836 if (res != NULL) {
13837 xmlXPathReleaseObject(ctxt->context, res);
13838 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013839 if (ctxt->value == tmp) {
13840 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013841 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013842 }
13843
13844 ctxt->context->node = NULL;
13845 }
13846
13847 /*
13848 * The result is used as the new evaluation locset.
13849 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013850 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013851 ctxt->context->node = NULL;
13852 ctxt->context->contextSize = -1;
13853 ctxt->context->proximityPosition = -1;
13854 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13855 ctxt->context->node = oldnode;
13856 return (total);
13857 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013858#endif /* LIBXML_XPTR_ENABLED */
13859
Daniel Veillardf06307e2001-07-03 10:35:50 +000013860 /*
13861 * Extract the old set, and then evaluate the result of the
13862 * expression for all the element in the set. use it to grow
13863 * up a new set.
13864 */
13865 CHECK_TYPE0(XPATH_NODESET);
13866 obj = valuePop(ctxt);
13867 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013868
Daniel Veillardf06307e2001-07-03 10:35:50 +000013869 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013870 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013871 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013872
Daniel Veillardf06307e2001-07-03 10:35:50 +000013873 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13874 ctxt->context->contextSize = 0;
13875 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013876/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013877 if (op->ch2 != -1)
13878 total +=
13879 xmlXPathCompOpEval(ctxt,
13880 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013881 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013882 res = valuePop(ctxt);
13883 if (res != NULL)
13884 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013885*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013886 valuePush(ctxt, obj);
13887 ctxt->context->node = oldnode;
13888 CHECK_ERROR0;
13889 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013890 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013891 /*
13892 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013893 * Also set the xpath document in case things like
13894 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013895 */
13896 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013897 /*
13898 * SPEC XPath 1.0:
13899 * "For each node in the node-set to be filtered, the
13900 * PredicateExpr is evaluated with that node as the
13901 * context node, with the number of nodes in the
13902 * node-set as the context size, and with the proximity
13903 * position of the node in the node-set with respect to
13904 * the axis as the context position;"
13905 * @oldset is the node-set" to be filtered.
13906 *
13907 * SPEC XPath 1.0:
13908 * "only predicates change the context position and
13909 * context size (see [2.4 Predicates])."
13910 * Example:
13911 * node-set context pos
13912 * nA 1
13913 * nB 2
13914 * nC 3
13915 * After applying predicate [position() > 1] :
13916 * node-set context pos
13917 * nB 1
13918 * nC 2
13919 *
13920 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013921 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013922 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013923 for (i = 0; i < oldset->nodeNr; i++) {
13924 /*
13925 * Run the evaluation with a node list made of
13926 * a single item in the nodeset.
13927 */
13928 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013929 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13930 (oldset->nodeTab[i]->doc != NULL))
13931 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013932 if (tmp == NULL) {
13933 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13934 ctxt->context->node);
13935 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013936 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13937 ctxt->context->node) < 0) {
13938 ctxt->error = XPATH_MEMORY_ERROR;
13939 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013940 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013941 valuePush(ctxt, tmp);
13942 ctxt->context->contextSize = oldset->nodeNr;
13943 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013944 /*
13945 * Evaluate the predicate against the context node.
13946 * Can/should we optimize position() predicates
13947 * here (e.g. "[1]")?
13948 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013949 if (op->ch2 != -1)
13950 total +=
13951 xmlXPathCompOpEval(ctxt,
13952 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013953 if (ctxt->error != XPATH_EXPRESSION_OK) {
13954 xmlXPathFreeNodeSet(newset);
13955 xmlXPathFreeObject(obj);
13956 return(0);
13957 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013958
Daniel Veillardf06307e2001-07-03 10:35:50 +000013959 /*
William M. Brack08171912003-12-29 02:52:11 +000013960 * The result of the evaluation needs to be tested to
13961 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013962 */
13963 /*
13964 * OPTIMIZE TODO: Can we use
13965 * xmlXPathNodeSetAdd*Unique()* instead?
13966 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013967 res = valuePop(ctxt);
13968 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013969 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13970 < 0)
13971 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013972 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013973
Daniel Veillardf06307e2001-07-03 10:35:50 +000013974 /*
13975 * Cleanup
13976 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013977 if (res != NULL) {
13978 xmlXPathReleaseObject(ctxt->context, res);
13979 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013980 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013981 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013982 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013983 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013984 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013985 * in order to avoid massive recreation inside this
13986 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013987 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013988 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013989 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013990 ctxt->context->node = NULL;
13991 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013992 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013993 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013994 /*
13995 * The result is used as the new evaluation set.
13996 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013997 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013998 ctxt->context->node = NULL;
13999 ctxt->context->contextSize = -1;
14000 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000014001 /* may want to move this past the '}' later */
14002 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014003 valuePush(ctxt,
14004 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014005 }
14006 ctxt->context->node = oldnode;
14007 return (total);
14008 }
14009 case XPATH_OP_SORT:
14010 if (op->ch1 != -1)
14011 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000014012 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014013 if ((ctxt->value != NULL) &&
14014 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000014015 (ctxt->value->nodesetval != NULL) &&
14016 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014017 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014018 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014019 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014020 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014021#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000014022 case XPATH_OP_RANGETO:{
14023 xmlXPathObjectPtr range;
14024 xmlXPathObjectPtr res, obj;
14025 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000014026 xmlLocationSetPtr newlocset = NULL;
14027 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014028 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000014029 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014030
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020014031 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014032 total +=
14033 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhoferd8083bf2016-06-25 12:35:50 +020014034 CHECK_ERROR0;
14035 }
14036 if (ctxt->value == NULL) {
14037 XP_ERROR0(XPATH_INVALID_OPERAND);
14038 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014039 if (op->ch2 == -1)
14040 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014041
William M. Brack08171912003-12-29 02:52:11 +000014042 if (ctxt->value->type == XPATH_LOCATIONSET) {
14043 /*
14044 * Extract the old locset, and then evaluate the result of the
14045 * expression for all the element in the locset. use it to grow
14046 * up a new locset.
14047 */
14048 CHECK_TYPE0(XPATH_LOCATIONSET);
14049 obj = valuePop(ctxt);
14050 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014051
William M. Brack08171912003-12-29 02:52:11 +000014052 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000014053 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000014054 ctxt->context->contextSize = 0;
14055 ctxt->context->proximityPosition = 0;
14056 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14057 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014058 if (res != NULL) {
14059 xmlXPathReleaseObject(ctxt->context, res);
14060 }
William M. Brack08171912003-12-29 02:52:11 +000014061 valuePush(ctxt, obj);
14062 CHECK_ERROR0;
14063 return (total);
14064 }
14065 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014066
William M. Brack08171912003-12-29 02:52:11 +000014067 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014068 /*
William M. Brack08171912003-12-29 02:52:11 +000014069 * Run the evaluation with a node list made of a
14070 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000014071 */
William M. Brackf7eb7942003-12-31 07:59:17 +000014072 ctxt->context->node = oldlocset->locTab[i]->user;
14073 ctxt->context->contextSize = oldlocset->locNr;
14074 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014075 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14076 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014077 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014078
Daniel Veillardf06307e2001-07-03 10:35:50 +000014079 if (op->ch2 != -1)
14080 total +=
14081 xmlXPathCompOpEval(ctxt,
14082 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014083 if (ctxt->error != XPATH_EXPRESSION_OK) {
14084 xmlXPathFreeObject(obj);
14085 return(0);
14086 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014087
Daniel Veillardf06307e2001-07-03 10:35:50 +000014088 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000014089 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014090 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000014091 (xmlLocationSetPtr)res->user;
14092 for (j=0; j<rloc->locNr; j++) {
14093 range = xmlXPtrNewRange(
14094 oldlocset->locTab[i]->user,
14095 oldlocset->locTab[i]->index,
14096 rloc->locTab[j]->user2,
14097 rloc->locTab[j]->index2);
14098 if (range != NULL) {
14099 xmlXPtrLocationSetAdd(newlocset, range);
14100 }
14101 }
14102 } else {
14103 range = xmlXPtrNewRangeNodeObject(
14104 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14105 if (range != NULL) {
14106 xmlXPtrLocationSetAdd(newlocset,range);
14107 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014108 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014109
Daniel Veillardf06307e2001-07-03 10:35:50 +000014110 /*
14111 * Cleanup
14112 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014113 if (res != NULL) {
14114 xmlXPathReleaseObject(ctxt->context, res);
14115 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014116 if (ctxt->value == tmp) {
14117 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014118 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014119 }
14120
14121 ctxt->context->node = NULL;
14122 }
William M. Brack72ee48d2003-12-30 08:30:19 +000014123 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000014124 CHECK_TYPE0(XPATH_NODESET);
14125 obj = valuePop(ctxt);
14126 oldset = obj->nodesetval;
14127 ctxt->context->node = NULL;
14128
14129 newlocset = xmlXPtrLocationSetCreate(NULL);
14130
14131 if (oldset != NULL) {
14132 for (i = 0; i < oldset->nodeNr; i++) {
14133 /*
14134 * Run the evaluation with a node list made of a single item
14135 * in the nodeset.
14136 */
14137 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014138 /*
14139 * OPTIMIZE TODO: Avoid recreation for every iteration.
14140 */
14141 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14142 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000014143 valuePush(ctxt, tmp);
14144
14145 if (op->ch2 != -1)
14146 total +=
14147 xmlXPathCompOpEval(ctxt,
14148 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014149 if (ctxt->error != XPATH_EXPRESSION_OK) {
14150 xmlXPathFreeObject(obj);
14151 return(0);
14152 }
William M. Brack08171912003-12-29 02:52:11 +000014153
William M. Brack08171912003-12-29 02:52:11 +000014154 res = valuePop(ctxt);
14155 range =
14156 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14157 res);
14158 if (range != NULL) {
14159 xmlXPtrLocationSetAdd(newlocset, range);
14160 }
14161
14162 /*
14163 * Cleanup
14164 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014165 if (res != NULL) {
14166 xmlXPathReleaseObject(ctxt->context, res);
14167 }
William M. Brack08171912003-12-29 02:52:11 +000014168 if (ctxt->value == tmp) {
14169 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014170 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000014171 }
14172
14173 ctxt->context->node = NULL;
14174 }
14175 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014176 }
14177
14178 /*
14179 * The result is used as the new evaluation set.
14180 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014181 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014182 ctxt->context->node = NULL;
14183 ctxt->context->contextSize = -1;
14184 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000014185 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014186 return (total);
14187 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014188#endif /* LIBXML_XPTR_ENABLED */
14189 }
14190 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000014191 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080014192 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014193 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014194}
14195
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014196/**
14197 * xmlXPathCompOpEvalToBoolean:
14198 * @ctxt: the XPath parser context
14199 *
14200 * Evaluates if the expression evaluates to true.
14201 *
14202 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14203 */
14204static int
14205xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014206 xmlXPathStepOpPtr op,
14207 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014208{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014209 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014210
14211start:
14212 /* comp = ctxt->comp; */
14213 switch (op->op) {
14214 case XPATH_OP_END:
14215 return (0);
14216 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014217 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014218 if (isPredicate)
14219 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14220 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014221 case XPATH_OP_SORT:
14222 /*
14223 * We don't need sorting for boolean results. Skip this one.
14224 */
14225 if (op->ch1 != -1) {
14226 op = &ctxt->comp->steps[op->ch1];
14227 goto start;
14228 }
14229 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014230 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014231 if (op->ch1 == -1)
14232 return(0);
14233
14234 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14235 if (ctxt->error != XPATH_EXPRESSION_OK)
14236 return(-1);
14237
14238 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14239 if (ctxt->error != XPATH_EXPRESSION_OK)
14240 return(-1);
14241
14242 resObj = valuePop(ctxt);
14243 if (resObj == NULL)
14244 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014245 break;
14246 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014247 /*
14248 * Fallback to call xmlXPathCompOpEval().
14249 */
14250 xmlXPathCompOpEval(ctxt, op);
14251 if (ctxt->error != XPATH_EXPRESSION_OK)
14252 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014253
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014254 resObj = valuePop(ctxt);
14255 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014256 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014257 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014258 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014259
14260 if (resObj) {
14261 int res;
14262
14263 if (resObj->type == XPATH_BOOLEAN) {
14264 res = resObj->boolval;
14265 } else if (isPredicate) {
14266 /*
14267 * For predicates a result of type "number" is handled
14268 * differently:
14269 * SPEC XPath 1.0:
14270 * "If the result is a number, the result will be converted
14271 * to true if the number is equal to the context position
14272 * and will be converted to false otherwise;"
14273 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014274 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014275 } else {
14276 res = xmlXPathCastToBoolean(resObj);
14277 }
14278 xmlXPathReleaseObject(ctxt->context, resObj);
14279 return(res);
14280 }
14281
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014282 return(0);
14283}
14284
Daniel Veillard56de87e2005-02-16 00:22:29 +000014285#ifdef XPATH_STREAMING
14286/**
14287 * xmlXPathRunStreamEval:
14288 * @ctxt: the XPath parser context with the compiled expression
14289 *
14290 * Evaluate the Precompiled Streamable XPath expression in the given context.
14291 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014292static int
14293xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14294 xmlXPathObjectPtr *resultSeq, int toBool)
14295{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014296 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014297 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014298 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014299 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014300 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014301 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014302
14303 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014304
14305 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014306 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014307 max_depth = xmlPatternMaxDepth(comp);
14308 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014309 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014310 if (max_depth == -2)
14311 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014312 min_depth = xmlPatternMinDepth(comp);
14313 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014314 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014315 from_root = xmlPatternFromRoot(comp);
14316 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014317 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014318#if 0
14319 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14320#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014321
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014322 if (! toBool) {
14323 if (resultSeq == NULL)
14324 return(-1);
14325 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14326 if (*resultSeq == NULL)
14327 return(-1);
14328 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014329
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014330 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014331 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014332 */
14333 if (min_depth == 0) {
14334 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014335 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014336 if (toBool)
14337 return(1);
14338 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014339 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014340 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014341 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014342 if (toBool)
14343 return(1);
14344 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014345 }
14346 }
14347 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014348 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014349 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014350
Daniel Veillard56de87e2005-02-16 00:22:29 +000014351 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014352 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014353 } else if (ctxt->node != NULL) {
14354 switch (ctxt->node->type) {
14355 case XML_ELEMENT_NODE:
14356 case XML_DOCUMENT_NODE:
14357 case XML_DOCUMENT_FRAG_NODE:
14358 case XML_HTML_DOCUMENT_NODE:
14359#ifdef LIBXML_DOCB_ENABLED
14360 case XML_DOCB_DOCUMENT_NODE:
14361#endif
14362 cur = ctxt->node;
14363 break;
14364 case XML_ATTRIBUTE_NODE:
14365 case XML_TEXT_NODE:
14366 case XML_CDATA_SECTION_NODE:
14367 case XML_ENTITY_REF_NODE:
14368 case XML_ENTITY_NODE:
14369 case XML_PI_NODE:
14370 case XML_COMMENT_NODE:
14371 case XML_NOTATION_NODE:
14372 case XML_DTD_NODE:
14373 case XML_DOCUMENT_TYPE_NODE:
14374 case XML_ELEMENT_DECL:
14375 case XML_ATTRIBUTE_DECL:
14376 case XML_ENTITY_DECL:
14377 case XML_NAMESPACE_DECL:
14378 case XML_XINCLUDE_START:
14379 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014380 break;
14381 }
14382 limit = cur;
14383 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014384 if (cur == NULL) {
14385 return(0);
14386 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014387
14388 patstream = xmlPatternGetStreamCtxt(comp);
14389 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014390 /*
14391 * QUESTION TODO: Is this an error?
14392 */
14393 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014394 }
14395
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014396 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014397
Daniel Veillard56de87e2005-02-16 00:22:29 +000014398 if (from_root) {
14399 ret = xmlStreamPush(patstream, NULL, NULL);
14400 if (ret < 0) {
14401 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014402 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014403 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014404 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014405 }
14406 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014407 depth = 0;
14408 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014409next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014410 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014411 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014412
14413 switch (cur->type) {
14414 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014415 case XML_TEXT_NODE:
14416 case XML_CDATA_SECTION_NODE:
14417 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014418 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014419 if (cur->type == XML_ELEMENT_NODE) {
14420 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014421 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014422 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014423 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14424 else
14425 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014426
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014427 if (ret < 0) {
14428 /* NOP. */
14429 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014430 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014431 goto return_1;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014432 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14433 < 0) {
14434 ctxt->lastError.domain = XML_FROM_XPATH;
14435 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14436 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014437 }
14438 if ((cur->children == NULL) || (depth >= max_depth)) {
14439 ret = xmlStreamPop(patstream);
14440 while (cur->next != NULL) {
14441 cur = cur->next;
14442 if ((cur->type != XML_ENTITY_DECL) &&
14443 (cur->type != XML_DTD_NODE))
14444 goto next_node;
14445 }
14446 }
14447 default:
14448 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014449 }
14450
Daniel Veillard56de87e2005-02-16 00:22:29 +000014451scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080014452 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014453 if ((cur->children != NULL) && (depth < max_depth)) {
14454 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014455 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014456 */
14457 if (cur->children->type != XML_ENTITY_DECL) {
14458 cur = cur->children;
14459 depth++;
14460 /*
14461 * Skip DTDs
14462 */
14463 if (cur->type != XML_DTD_NODE)
14464 continue;
14465 }
14466 }
14467
14468 if (cur == limit)
14469 break;
14470
14471 while (cur->next != NULL) {
14472 cur = cur->next;
14473 if ((cur->type != XML_ENTITY_DECL) &&
14474 (cur->type != XML_DTD_NODE))
14475 goto next_node;
14476 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014477
Daniel Veillard56de87e2005-02-16 00:22:29 +000014478 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014479 cur = cur->parent;
14480 depth--;
14481 if ((cur == NULL) || (cur == limit))
14482 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014483 if (cur->type == XML_ELEMENT_NODE) {
14484 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014485 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014486 ((cur->type == XML_TEXT_NODE) ||
14487 (cur->type == XML_CDATA_SECTION_NODE) ||
14488 (cur->type == XML_COMMENT_NODE) ||
14489 (cur->type == XML_PI_NODE)))
14490 {
14491 ret = xmlStreamPop(patstream);
14492 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014493 if (cur->next != NULL) {
14494 cur = cur->next;
14495 break;
14496 }
14497 } while (cur != NULL);
14498
14499 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014500
Daniel Veillard56de87e2005-02-16 00:22:29 +000014501done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014502
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014503#if 0
14504 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014505 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014506#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014507
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014508 if (patstream)
14509 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014510 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014511
14512return_1:
14513 if (patstream)
14514 xmlFreeStreamCtxt(patstream);
14515 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014516}
14517#endif /* XPATH_STREAMING */
14518
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014519/**
14520 * xmlXPathRunEval:
14521 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014522 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014523 *
14524 * Evaluate the Precompiled XPath expression in the given context.
14525 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014526static int
14527xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14528{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014529 xmlXPathCompExprPtr comp;
14530
14531 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014532 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014533
14534 if (ctxt->valueTab == NULL) {
14535 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014536 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014537 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14538 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014539 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014540 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014541 }
14542 ctxt->valueNr = 0;
14543 ctxt->valueMax = 10;
14544 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014545 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014546 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014547#ifdef XPATH_STREAMING
14548 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014549 int res;
14550
14551 if (toBool) {
14552 /*
14553 * Evaluation to boolean result.
14554 */
14555 res = xmlXPathRunStreamEval(ctxt->context,
14556 ctxt->comp->stream, NULL, 1);
14557 if (res != -1)
14558 return(res);
14559 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014560 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014561
14562 /*
14563 * Evaluation to a sequence.
14564 */
14565 res = xmlXPathRunStreamEval(ctxt->context,
14566 ctxt->comp->stream, &resObj, 0);
14567
14568 if ((res != -1) && (resObj != NULL)) {
14569 valuePush(ctxt, resObj);
14570 return(0);
14571 }
14572 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014573 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014574 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014575 /*
14576 * QUESTION TODO: This falls back to normal XPath evaluation
14577 * if res == -1. Is this intended?
14578 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014579 }
14580#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014581 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014582 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014583 xmlGenericError(xmlGenericErrorContext,
14584 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014585 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014586 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014587 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014588 return(xmlXPathCompOpEvalToBoolean(ctxt,
14589 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014590 else
14591 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14592
14593 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014594}
14595
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014596/************************************************************************
14597 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014598 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014599 * *
14600 ************************************************************************/
14601
14602/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014603 * xmlXPathEvalPredicate:
14604 * @ctxt: the XPath context
14605 * @res: the Predicate Expression evaluation result
14606 *
14607 * Evaluate a predicate result for the current node.
14608 * A PredicateExpr is evaluated by evaluating the Expr and converting
14609 * the result to a boolean. If the result is a number, the result will
14610 * be converted to true if the number is equal to the position of the
14611 * context node in the context node list (as returned by the position
14612 * function) and will be converted to false otherwise; if the result
14613 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014614 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014615 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014616 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014617 */
14618int
14619xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014620 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014621 switch (res->type) {
14622 case XPATH_BOOLEAN:
14623 return(res->boolval);
14624 case XPATH_NUMBER:
14625 return(res->floatval == ctxt->proximityPosition);
14626 case XPATH_NODESET:
14627 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014628 if (res->nodesetval == NULL)
14629 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014630 return(res->nodesetval->nodeNr != 0);
14631 case XPATH_STRING:
14632 return((res->stringval != NULL) &&
14633 (xmlStrlen(res->stringval) != 0));
14634 default:
14635 STRANGE
14636 }
14637 return(0);
14638}
14639
14640/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014641 * xmlXPathEvaluatePredicateResult:
14642 * @ctxt: the XPath Parser context
14643 * @res: the Predicate Expression evaluation result
14644 *
14645 * Evaluate a predicate result for the current node.
14646 * A PredicateExpr is evaluated by evaluating the Expr and converting
14647 * the result to a boolean. If the result is a number, the result will
14648 * be converted to true if the number is equal to the position of the
14649 * context node in the context node list (as returned by the position
14650 * function) and will be converted to false otherwise; if the result
14651 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014652 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014653 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014654 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014655 */
14656int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014657xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014658 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014659 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014660 switch (res->type) {
14661 case XPATH_BOOLEAN:
14662 return(res->boolval);
14663 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014664#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014665 return((res->floatval == ctxt->context->proximityPosition) &&
14666 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014667#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014668 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014669#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014670 case XPATH_NODESET:
14671 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014672 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014673 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014674 return(res->nodesetval->nodeNr != 0);
14675 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014676 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014677#ifdef LIBXML_XPTR_ENABLED
14678 case XPATH_LOCATIONSET:{
14679 xmlLocationSetPtr ptr = res->user;
14680 if (ptr == NULL)
14681 return(0);
14682 return (ptr->locNr != 0);
14683 }
14684#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014685 default:
14686 STRANGE
14687 }
14688 return(0);
14689}
14690
Daniel Veillard56de87e2005-02-16 00:22:29 +000014691#ifdef XPATH_STREAMING
14692/**
14693 * xmlXPathTryStreamCompile:
14694 * @ctxt: an XPath context
14695 * @str: the XPath expression
14696 *
14697 * Try to compile the XPath expression as a streamable subset.
14698 *
14699 * Returns the compiled expression or NULL if failed to compile.
14700 */
14701static xmlXPathCompExprPtr
14702xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14703 /*
14704 * Optimization: use streaming patterns when the XPath expression can
14705 * be compiled to a stream lookup
14706 */
14707 xmlPatternPtr stream;
14708 xmlXPathCompExprPtr comp;
14709 xmlDictPtr dict = NULL;
14710 const xmlChar **namespaces = NULL;
14711 xmlNsPtr ns;
14712 int i, j;
14713
14714 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14715 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014716 const xmlChar *tmp;
14717
14718 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014719 * We don't try to handle expressions using the verbose axis
14720 * specifiers ("::"), just the simplied form at this point.
14721 * Additionally, if there is no list of namespaces available and
14722 * there's a ":" in the expression, indicating a prefixed QName,
14723 * then we won't try to compile either. xmlPatterncompile() needs
14724 * to have a list of namespaces at compilation time in order to
14725 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014726 */
14727 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014728 if ((tmp != NULL) &&
14729 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014730 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014731
Daniel Veillard56de87e2005-02-16 00:22:29 +000014732 if (ctxt != NULL) {
14733 dict = ctxt->dict;
14734 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014735 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014736 if (namespaces == NULL) {
14737 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14738 return(NULL);
14739 }
14740 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14741 ns = ctxt->namespaces[j];
14742 namespaces[i++] = ns->href;
14743 namespaces[i++] = ns->prefix;
14744 }
14745 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014746 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014747 }
14748 }
14749
William M. Brackea152c02005-06-09 18:12:28 +000014750 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14751 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014752 if (namespaces != NULL) {
14753 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014754 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014755 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14756 comp = xmlXPathNewCompExpr();
14757 if (comp == NULL) {
14758 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14759 return(NULL);
14760 }
14761 comp->stream = stream;
14762 comp->dict = dict;
14763 if (comp->dict)
14764 xmlDictReference(comp->dict);
14765 return(comp);
14766 }
14767 xmlFreePattern(stream);
14768 }
14769 return(NULL);
14770}
14771#endif /* XPATH_STREAMING */
14772
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014773static void
Nick Wellnhofer62270532012-08-19 19:42:38 +020014774xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014775{
14776 /*
14777 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14778 * internal representation.
14779 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014780
Nick Wellnhoferb4bcba22013-08-05 00:15:11 +020014781 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14782 (op->ch1 != -1) &&
14783 (op->ch2 == -1 /* no predicate */))
Nick Wellnhofer62270532012-08-19 19:42:38 +020014784 {
14785 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14786
14787 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14788 ((xmlXPathAxisVal) prevop->value ==
14789 AXIS_DESCENDANT_OR_SELF) &&
14790 (prevop->ch2 == -1) &&
14791 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14792 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14793 {
14794 /*
14795 * This is a "descendant-or-self::node()" without predicates.
14796 * Try to eliminate it.
14797 */
14798
14799 switch ((xmlXPathAxisVal) op->value) {
14800 case AXIS_CHILD:
14801 case AXIS_DESCENDANT:
14802 /*
14803 * Convert "descendant-or-self::node()/child::" or
14804 * "descendant-or-self::node()/descendant::" to
14805 * "descendant::"
14806 */
14807 op->ch1 = prevop->ch1;
14808 op->value = AXIS_DESCENDANT;
14809 break;
14810 case AXIS_SELF:
14811 case AXIS_DESCENDANT_OR_SELF:
14812 /*
14813 * Convert "descendant-or-self::node()/self::" or
14814 * "descendant-or-self::node()/descendant-or-self::" to
14815 * to "descendant-or-self::"
14816 */
14817 op->ch1 = prevop->ch1;
14818 op->value = AXIS_DESCENDANT_OR_SELF;
14819 break;
14820 default:
14821 break;
14822 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014823 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014824 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014825
Nick Wellnhofer839689a2016-04-27 18:00:12 +020014826 /* OP_VALUE has invalid ch1. */
14827 if (op->op == XPATH_OP_VALUE)
14828 return;
14829
Nick Wellnhofer62270532012-08-19 19:42:38 +020014830 /* Recurse */
14831 if (op->ch1 != -1)
14832 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014833 if (op->ch2 != -1)
Nick Wellnhofer62270532012-08-19 19:42:38 +020014834 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014835}
14836
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014837/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014838 * xmlXPathCtxtCompile:
14839 * @ctxt: an XPath context
14840 * @str: the XPath expression
14841 *
14842 * Compile an XPath expression
14843 *
14844 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14845 * the caller has to free the object.
14846 */
14847xmlXPathCompExprPtr
14848xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14849 xmlXPathParserContextPtr pctxt;
14850 xmlXPathCompExprPtr comp;
14851
Daniel Veillard56de87e2005-02-16 00:22:29 +000014852#ifdef XPATH_STREAMING
14853 comp = xmlXPathTryStreamCompile(ctxt, str);
14854 if (comp != NULL)
14855 return(comp);
14856#endif
14857
Daniel Veillard4773df22004-01-23 13:15:13 +000014858 xmlXPathInit();
14859
14860 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014861 if (pctxt == NULL)
14862 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014863 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014864
14865 if( pctxt->error != XPATH_EXPRESSION_OK )
14866 {
14867 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014868 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014869 }
14870
14871 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014872 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014873 * aleksey: in some cases this line prints *second* error message
14874 * (see bug #78858) and probably this should be fixed.
14875 * However, we are not sure that all error messages are printed
14876 * out in other places. It's not critical so we leave it as-is for now
14877 */
14878 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14879 comp = NULL;
14880 } else {
14881 comp = pctxt->comp;
14882 pctxt->comp = NULL;
14883 }
14884 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014885
Daniel Veillard4773df22004-01-23 13:15:13 +000014886 if (comp != NULL) {
14887 comp->expr = xmlStrdup(str);
14888#ifdef DEBUG_EVAL_COUNTS
14889 comp->string = xmlStrdup(str);
14890 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014891#endif
Nick Wellnhofer62270532012-08-19 19:42:38 +020014892 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14893 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014894 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014895 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014896 return(comp);
14897}
14898
14899/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014900 * xmlXPathCompile:
14901 * @str: the XPath expression
14902 *
14903 * Compile an XPath expression
14904 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014905 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014906 * the caller has to free the object.
14907 */
14908xmlXPathCompExprPtr
14909xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014910 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014911}
14912
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014913/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014914 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014915 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014916 * @ctxt: the XPath context
14917 * @resObj: the resulting XPath object or NULL
14918 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014919 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014920 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014921 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014922 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014923 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014924 * the caller has to free the object.
14925 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014926static int
14927xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14928 xmlXPathContextPtr ctxt,
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014929 xmlXPathObjectPtr *resObjPtr,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014930 int toBool)
14931{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014932 xmlXPathParserContextPtr pctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014933 xmlXPathObjectPtr resObj;
Daniel Veillard81463942001-10-16 12:34:39 +000014934#ifndef LIBXML_THREAD_ENABLED
14935 static int reentance = 0;
14936#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014937 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014938
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014939 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014940
14941 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014942 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014943 xmlXPathInit();
14944
Daniel Veillard81463942001-10-16 12:34:39 +000014945#ifndef LIBXML_THREAD_ENABLED
14946 reentance++;
14947 if (reentance > 1)
14948 xmlXPathDisableOptimizer = 1;
14949#endif
14950
Daniel Veillardf06307e2001-07-03 10:35:50 +000014951#ifdef DEBUG_EVAL_COUNTS
14952 comp->nb++;
14953 if ((comp->string != NULL) && (comp->nb > 100)) {
14954 fprintf(stderr, "100 x %s\n", comp->string);
14955 comp->nb = 0;
14956 }
14957#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014958 pctxt = xmlXPathCompParserContext(comp, ctxt);
14959 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014960
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014961 if (pctxt->error != XPATH_EXPRESSION_OK) {
14962 resObj = NULL;
14963 } else {
14964 resObj = valuePop(pctxt);
14965 if (resObj == NULL) {
Nick Wellnhofera07a4e92017-05-27 17:04:12 +020014966 if (!toBool)
14967 xmlGenericError(xmlGenericErrorContext,
14968 "xmlXPathCompiledEval: No result on the stack.\n");
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014969 } else if (pctxt->valueNr > 0) {
14970 xmlGenericError(xmlGenericErrorContext,
14971 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14972 pctxt->valueNr);
14973 }
Owen Taylor3473f882001-02-23 17:55:21 +000014974 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014975
Nick Wellnhoferc8519702017-05-27 15:26:11 +020014976 if (resObjPtr)
14977 *resObjPtr = resObj;
14978 else
14979 xmlXPathReleaseObject(ctxt, resObj);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014980
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014981 pctxt->comp = NULL;
14982 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014983#ifndef LIBXML_THREAD_ENABLED
14984 reentance--;
14985#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014986
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014987 return(res);
14988}
14989
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014990/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014991 * xmlXPathCompiledEval:
14992 * @comp: the compiled XPath expression
14993 * @ctx: the XPath context
14994 *
14995 * Evaluate the Precompiled XPath expression in the given context.
14996 *
14997 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14998 * the caller has to free the object.
14999 */
15000xmlXPathObjectPtr
15001xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
15002{
15003 xmlXPathObjectPtr res = NULL;
15004
15005 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
15006 return(res);
15007}
15008
15009/**
15010 * xmlXPathCompiledEvalToBoolean:
15011 * @comp: the compiled XPath expression
15012 * @ctxt: the XPath context
15013 *
15014 * Applies the XPath boolean() function on the result of the given
15015 * compiled expression.
15016 *
15017 * Returns 1 if the expression evaluated to true, 0 if to false and
15018 * -1 in API and internal errors.
15019 */
15020int
15021xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
15022 xmlXPathContextPtr ctxt)
15023{
15024 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
15025}
15026
15027/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000015028 * xmlXPathEvalExpr:
15029 * @ctxt: the XPath Parser context
15030 *
15031 * Parse and evaluate an XPath expression in the given context,
15032 * then push the result on the context stack
15033 */
15034void
15035xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000015036#ifdef XPATH_STREAMING
15037 xmlXPathCompExprPtr comp;
15038#endif
15039
Daniel Veillarda82b1822004-11-08 16:24:57 +000015040 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015041
Daniel Veillard56de87e2005-02-16 00:22:29 +000015042#ifdef XPATH_STREAMING
15043 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15044 if (comp != NULL) {
15045 if (ctxt->comp != NULL)
15046 xmlXPathFreeCompExpr(ctxt->comp);
15047 ctxt->comp = comp;
Daniel Veillard56de87e2005-02-16 00:22:29 +000015048 } else
15049#endif
15050 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000015051 xmlXPathCompileExpr(ctxt, 1);
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020015052 CHECK_ERROR;
15053
15054 /* Check for trailing characters. */
15055 if (*ctxt->cur != 0)
15056 XP_ERROR(XPATH_EXPR_ERROR);
15057
15058 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
Nick Wellnhofer62270532012-08-19 19:42:38 +020015059 xmlXPathOptimizeExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000015060 &ctxt->comp->steps[ctxt->comp->last]);
Daniel Veillard56de87e2005-02-16 00:22:29 +000015061 }
Nick Wellnhoferaed407c2017-05-25 16:57:14 +020015062
Daniel Veillard45490ae2008-07-29 09:13:19 +000015063 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000015064}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015065
15066/**
15067 * xmlXPathEval:
15068 * @str: the XPath expression
15069 * @ctx: the XPath context
15070 *
15071 * Evaluate the XPath Location Path in the given context.
15072 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000015073 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015074 * the caller has to free the object.
15075 */
15076xmlXPathObjectPtr
15077xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15078 xmlXPathParserContextPtr ctxt;
Nick Wellnhoferc8519702017-05-27 15:26:11 +020015079 xmlXPathObjectPtr res;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015080
William M. Brackf13f77f2004-11-12 16:03:48 +000015081 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015082
William M. Brackf13f77f2004-11-12 16:03:48 +000015083 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015084
15085 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000015086 if (ctxt == NULL)
15087 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015088 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015089
Nick Wellnhoferc8519702017-05-27 15:26:11 +020015090 if (ctxt->error != XPATH_EXPRESSION_OK) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015091 res = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015092 } else {
15093 res = valuePop(ctxt);
Nick Wellnhoferc8519702017-05-27 15:26:11 +020015094 if (res == NULL) {
15095 xmlGenericError(xmlGenericErrorContext,
15096 "xmlXPathCompiledEval: No result on the stack.\n");
15097 } else if (ctxt->valueNr > 0) {
15098 xmlGenericError(xmlGenericErrorContext,
15099 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
15100 ctxt->valueNr);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015101 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015102 }
15103
Owen Taylor3473f882001-02-23 17:55:21 +000015104 xmlXPathFreeParserContext(ctxt);
15105 return(res);
15106}
15107
15108/**
Alex Bligh28876af2013-03-23 17:23:27 +000015109 * xmlXPathSetContextNode:
15110 * @node: the node to to use as the context node
15111 * @ctx: the XPath context
15112 *
15113 * Sets 'node' as the context node. The node must be in the same
15114 * document as that associated with the context.
15115 *
15116 * Returns -1 in case of error or 0 if successful
15117 */
15118int
15119xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15120 if ((node == NULL) || (ctx == NULL))
15121 return(-1);
15122
15123 if (node->doc == ctx->doc) {
15124 ctx->node = node;
15125 return(0);
15126 }
15127 return(-1);
15128}
15129
15130/**
15131 * xmlXPathNodeEval:
15132 * @node: the node to to use as the context node
15133 * @str: the XPath expression
15134 * @ctx: the XPath context
15135 *
15136 * Evaluate the XPath Location Path in the given context. The node 'node'
15137 * is set as the context node. The context node is not restored.
15138 *
15139 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15140 * the caller has to free the object.
15141 */
15142xmlXPathObjectPtr
15143xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15144 if (str == NULL)
15145 return(NULL);
15146 if (xmlXPathSetContextNode(node, ctx) < 0)
15147 return(NULL);
15148 return(xmlXPathEval(str, ctx));
15149}
15150
15151/**
Owen Taylor3473f882001-02-23 17:55:21 +000015152 * xmlXPathEvalExpression:
15153 * @str: the XPath expression
15154 * @ctxt: the XPath context
15155 *
Daniel Veillarddbb828f2017-08-28 20:38:53 +020015156 * Alias for xmlXPathEval().
15157 *
15158 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15159 * the caller has to free the object.
Owen Taylor3473f882001-02-23 17:55:21 +000015160 */
15161xmlXPathObjectPtr
15162xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Nick Wellnhofer640a3682017-05-27 14:59:49 +020015163 return(xmlXPathEval(str, ctxt));
Owen Taylor3473f882001-02-23 17:55:21 +000015164}
15165
Daniel Veillard42766c02002-08-22 20:52:17 +000015166/************************************************************************
15167 * *
15168 * Extra functions not pertaining to the XPath spec *
15169 * *
15170 ************************************************************************/
15171/**
15172 * xmlXPathEscapeUriFunction:
15173 * @ctxt: the XPath Parser context
15174 * @nargs: the number of arguments
15175 *
15176 * Implement the escape-uri() XPath function
15177 * string escape-uri(string $str, bool $escape-reserved)
15178 *
15179 * This function applies the URI escaping rules defined in section 2 of [RFC
15180 * 2396] to the string supplied as $uri-part, which typically represents all
15181 * or part of a URI. The effect of the function is to replace any special
15182 * character in the string by an escape sequence of the form %xx%yy...,
15183 * where xxyy... is the hexadecimal representation of the octets used to
15184 * represent the character in UTF-8.
15185 *
15186 * The set of characters that are escaped depends on the setting of the
15187 * boolean argument $escape-reserved.
15188 *
15189 * If $escape-reserved is true, all characters are escaped other than lower
15190 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15191 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15192 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15193 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15194 * A-F).
15195 *
15196 * If $escape-reserved is false, the behavior differs in that characters
15197 * referred to in [RFC 2396] as reserved characters are not escaped. These
15198 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015199 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015200 * [RFC 2396] does not define whether escaped URIs should use lower case or
15201 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15202 * compared using string comparison functions, this function must always use
15203 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015204 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015205 * Generally, $escape-reserved should be set to true when escaping a string
15206 * that is to form a single part of a URI, and to false when escaping an
15207 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015208 *
15209 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015210 * utf-8 and then converted according to RFC 2396.
15211 *
15212 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015213 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015214 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15215 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15216 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15217 *
15218 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015219static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015220xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15221 xmlXPathObjectPtr str;
15222 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080015223 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000015224 xmlChar *cptr;
15225 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015226
Daniel Veillard42766c02002-08-22 20:52:17 +000015227 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015228
Daniel Veillard42766c02002-08-22 20:52:17 +000015229 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015230
Daniel Veillard42766c02002-08-22 20:52:17 +000015231 CAST_TO_STRING;
15232 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015233
Daniel Veillardade10f22012-07-12 09:43:27 +080015234 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015235
Daniel Veillard42766c02002-08-22 20:52:17 +000015236 escape[0] = '%';
15237 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015238
Daniel Veillard42766c02002-08-22 20:52:17 +000015239 if (target) {
15240 for (cptr = str->stringval; *cptr; cptr++) {
15241 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15242 (*cptr >= 'a' && *cptr <= 'z') ||
15243 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015244 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015245 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15246 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015247 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015248 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15249 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15250 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15251 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15252 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15253 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15254 (!escape_reserved &&
15255 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15256 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15257 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15258 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080015259 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000015260 } else {
15261 if ((*cptr >> 4) < 10)
15262 escape[1] = '0' + (*cptr >> 4);
15263 else
15264 escape[1] = 'A' - 10 + (*cptr >> 4);
15265 if ((*cptr & 0xF) < 10)
15266 escape[2] = '0' + (*cptr & 0xF);
15267 else
15268 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015269
Daniel Veillardade10f22012-07-12 09:43:27 +080015270 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000015271 }
15272 }
15273 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015274 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080015275 xmlBufContent(target)));
15276 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015277 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015278}
15279
Owen Taylor3473f882001-02-23 17:55:21 +000015280/**
15281 * xmlXPathRegisterAllFunctions:
15282 * @ctxt: the XPath context
15283 *
15284 * Registers all default XPath functions in this context
15285 */
15286void
15287xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15288{
15289 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15290 xmlXPathBooleanFunction);
15291 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15292 xmlXPathCeilingFunction);
15293 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15294 xmlXPathCountFunction);
15295 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15296 xmlXPathConcatFunction);
15297 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15298 xmlXPathContainsFunction);
15299 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15300 xmlXPathIdFunction);
15301 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15302 xmlXPathFalseFunction);
15303 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15304 xmlXPathFloorFunction);
15305 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15306 xmlXPathLastFunction);
15307 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15308 xmlXPathLangFunction);
15309 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15310 xmlXPathLocalNameFunction);
15311 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15312 xmlXPathNotFunction);
15313 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15314 xmlXPathNameFunction);
15315 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15316 xmlXPathNamespaceURIFunction);
15317 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15318 xmlXPathNormalizeFunction);
15319 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15320 xmlXPathNumberFunction);
15321 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15322 xmlXPathPositionFunction);
15323 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15324 xmlXPathRoundFunction);
15325 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15326 xmlXPathStringFunction);
15327 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15328 xmlXPathStringLengthFunction);
15329 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15330 xmlXPathStartsWithFunction);
15331 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15332 xmlXPathSubstringFunction);
15333 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15334 xmlXPathSubstringBeforeFunction);
15335 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15336 xmlXPathSubstringAfterFunction);
15337 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15338 xmlXPathSumFunction);
15339 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15340 xmlXPathTrueFunction);
15341 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15342 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015343
15344 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15345 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15346 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015347}
15348
15349#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015350#define bottom_xpath
15351#include "elfgcchack.h"