blob: 3472ff0563d9cf96428b24e4586ca6ef339f47a0 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005 *f
Owen Taylor3473f882001-02-23 17:55:21 +00006 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Daniel Veillard56de87e2005-02-16 00:22:29 +000054#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
Daniel Veillardade10f22012-07-12 09:43:27 +080058#include "buf.h"
59
Daniel Veillard56de87e2005-02-16 00:22:29 +000060#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000061#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000062#endif
Owen Taylor3473f882001-02-23 17:55:21 +000063
Daniel Veillard45490ae2008-07-29 09:13:19 +000064#define TODO \
Daniel Veillardd96f6d32003-10-07 21:25:12 +000065 xmlGenericError(xmlGenericErrorContext, \
66 "Unimplemented block at %s:%d\n", \
67 __FILE__, __LINE__);
68
Vojtech Fried3e031b72012-08-24 16:52:44 +080069/**
70 * WITH_TIM_SORT:
71 *
72 * Use the Timsort algorithm provided in timsort.h to sort
73 * nodeset as this is a great improvement over the old Shell sort
74 * used in xmlXPathNodeSetSort()
75 */
76#define WITH_TIM_SORT
77
William M. Brackd1757ab2004-10-02 22:07:48 +000078/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000079* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000080* If defined, this will use xmlXPathCmpNodesExt() instead of
81* xmlXPathCmpNodes(). The new function is optimized comparison of
82* non-element nodes; actually it will speed up comparison only if
83* xmlXPathOrderDocElems() was called in order to index the elements of
84* a tree in document order; Libxslt does such an indexing, thus it will
85* benefit from this optimization.
86*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000087#define XP_OPTIMIZED_NON_ELEM_COMPARISON
88
89/*
90* XP_OPTIMIZED_FILTER_FIRST:
91* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
92* in a way, that it stop evaluation at the first node.
Daniel Veillard45490ae2008-07-29 09:13:19 +000093*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000094#define XP_OPTIMIZED_FILTER_FIRST
95
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000096/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000097* XP_DEBUG_OBJ_USAGE:
98* Internal flag to enable tracking of how much XPath objects have been
99* created.
100*/
101/* #define XP_DEBUG_OBJ_USAGE */
102
103/*
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800104 * XPATH_MAX_STEPS:
105 * when compiling an XPath expression we arbitrary limit the maximum
106 * number of step operation in the compiled expression. 1000000 is
107 * an insanely large value which should never be reached under normal
108 * circumstances
109 */
110#define XPATH_MAX_STEPS 1000000
111
112/*
113 * XPATH_MAX_STACK_DEPTH:
114 * when evaluating an XPath expression we arbitrary limit the maximum
115 * number of object allowed to be pushed on the stack. 1000000 is
116 * an insanely large value which should never be reached under normal
117 * circumstances
118 */
119#define XPATH_MAX_STACK_DEPTH 1000000
120
121/*
122 * XPATH_MAX_NODESET_LENGTH:
123 * when evaluating an XPath expression nodesets are created and we
124 * arbitrary limit the maximum length of those node set. 10000000 is
125 * an insanely large value which should never be reached under normal
126 * circumstances, one would first need to construct an in memory tree
127 * with more than 10 millions nodes.
128 */
129#define XPATH_MAX_NODESET_LENGTH 10000000
130
131/*
William M. Brackd1757ab2004-10-02 22:07:48 +0000132 * TODO:
133 * There are a few spots where some tests are done which depend upon ascii
134 * data. These should be enhanced for full UTF8 support (see particularly
135 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
136 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000137
Denis Pauke28c8a12013-08-03 14:22:54 +0300138#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
139/**
140 * xmlXPathCmpNodesExt:
141 * @node1: the first node
142 * @node2: the second node
143 *
144 * Compare two nodes w.r.t document order.
145 * This one is optimized for handling of non-element nodes.
146 *
147 * Returns -2 in case of error 1 if first point < second point, 0 if
148 * it's the same node, -1 otherwise
149 */
150static int
151xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
152 int depth1, depth2;
153 int misc = 0, precedence1 = 0, precedence2 = 0;
154 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
155 xmlNodePtr cur, root;
156 long l1, l2;
157
158 if ((node1 == NULL) || (node2 == NULL))
159 return(-2);
160
161 if (node1 == node2)
162 return(0);
163
164 /*
165 * a couple of optimizations which will avoid computations in most cases
166 */
167 switch (node1->type) {
168 case XML_ELEMENT_NODE:
169 if (node2->type == XML_ELEMENT_NODE) {
170 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
171 (0 > (long) node2->content) &&
172 (node1->doc == node2->doc))
173 {
174 l1 = -((long) node1->content);
175 l2 = -((long) node2->content);
176 if (l1 < l2)
177 return(1);
178 if (l1 > l2)
179 return(-1);
180 } else
181 goto turtle_comparison;
182 }
183 break;
184 case XML_ATTRIBUTE_NODE:
185 precedence1 = 1; /* element is owner */
186 miscNode1 = node1;
187 node1 = node1->parent;
188 misc = 1;
189 break;
190 case XML_TEXT_NODE:
191 case XML_CDATA_SECTION_NODE:
192 case XML_COMMENT_NODE:
193 case XML_PI_NODE: {
194 miscNode1 = node1;
195 /*
196 * Find nearest element node.
197 */
198 if (node1->prev != NULL) {
199 do {
200 node1 = node1->prev;
201 if (node1->type == XML_ELEMENT_NODE) {
202 precedence1 = 3; /* element in prev-sibl axis */
203 break;
204 }
205 if (node1->prev == NULL) {
206 precedence1 = 2; /* element is parent */
207 /*
208 * URGENT TODO: Are there any cases, where the
209 * parent of such a node is not an element node?
210 */
211 node1 = node1->parent;
212 break;
213 }
214 } while (1);
215 } else {
216 precedence1 = 2; /* element is parent */
217 node1 = node1->parent;
218 }
219 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
220 (0 <= (long) node1->content)) {
221 /*
222 * Fallback for whatever case.
223 */
224 node1 = miscNode1;
225 precedence1 = 0;
226 } else
227 misc = 1;
228 }
229 break;
230 case XML_NAMESPACE_DECL:
231 /*
232 * TODO: why do we return 1 for namespace nodes?
233 */
234 return(1);
235 default:
236 break;
237 }
238 switch (node2->type) {
239 case XML_ELEMENT_NODE:
240 break;
241 case XML_ATTRIBUTE_NODE:
242 precedence2 = 1; /* element is owner */
243 miscNode2 = node2;
244 node2 = node2->parent;
245 misc = 1;
246 break;
247 case XML_TEXT_NODE:
248 case XML_CDATA_SECTION_NODE:
249 case XML_COMMENT_NODE:
250 case XML_PI_NODE: {
251 miscNode2 = node2;
252 if (node2->prev != NULL) {
253 do {
254 node2 = node2->prev;
255 if (node2->type == XML_ELEMENT_NODE) {
256 precedence2 = 3; /* element in prev-sibl axis */
257 break;
258 }
259 if (node2->prev == NULL) {
260 precedence2 = 2; /* element is parent */
261 node2 = node2->parent;
262 break;
263 }
264 } while (1);
265 } else {
266 precedence2 = 2; /* element is parent */
267 node2 = node2->parent;
268 }
269 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
Gauravfcd45832013-11-28 23:01:44 +0800270 (0 <= (long) node2->content))
Denis Pauke28c8a12013-08-03 14:22:54 +0300271 {
272 node2 = miscNode2;
273 precedence2 = 0;
274 } else
275 misc = 1;
276 }
277 break;
278 case XML_NAMESPACE_DECL:
279 return(1);
280 default:
281 break;
282 }
283 if (misc) {
284 if (node1 == node2) {
285 if (precedence1 == precedence2) {
286 /*
287 * The ugly case; but normally there aren't many
288 * adjacent non-element nodes around.
289 */
290 cur = miscNode2->prev;
291 while (cur != NULL) {
292 if (cur == miscNode1)
293 return(1);
294 if (cur->type == XML_ELEMENT_NODE)
295 return(-1);
296 cur = cur->prev;
297 }
298 return (-1);
299 } else {
300 /*
301 * Evaluate based on higher precedence wrt to the element.
302 * TODO: This assumes attributes are sorted before content.
303 * Is this 100% correct?
304 */
305 if (precedence1 < precedence2)
306 return(1);
307 else
308 return(-1);
309 }
310 }
311 /*
312 * Special case: One of the helper-elements is contained by the other.
313 * <foo>
314 * <node2>
315 * <node1>Text-1(precedence1 == 2)</node1>
316 * </node2>
317 * Text-6(precedence2 == 3)
318 * </foo>
319 */
320 if ((precedence2 == 3) && (precedence1 > 1)) {
321 cur = node1->parent;
322 while (cur) {
323 if (cur == node2)
324 return(1);
325 cur = cur->parent;
326 }
327 }
328 if ((precedence1 == 3) && (precedence2 > 1)) {
329 cur = node2->parent;
330 while (cur) {
331 if (cur == node1)
332 return(-1);
333 cur = cur->parent;
334 }
335 }
336 }
337
338 /*
339 * Speedup using document order if availble.
340 */
341 if ((node1->type == XML_ELEMENT_NODE) &&
342 (node2->type == XML_ELEMENT_NODE) &&
343 (0 > (long) node1->content) &&
344 (0 > (long) node2->content) &&
345 (node1->doc == node2->doc)) {
346
347 l1 = -((long) node1->content);
348 l2 = -((long) node2->content);
349 if (l1 < l2)
350 return(1);
351 if (l1 > l2)
352 return(-1);
353 }
354
355turtle_comparison:
356
357 if (node1 == node2->prev)
358 return(1);
359 if (node1 == node2->next)
360 return(-1);
361 /*
362 * compute depth to root
363 */
Xin Li28c53d32017-03-07 00:33:02 +0000364 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
365 if (cur->parent == node1)
Denis Pauke28c8a12013-08-03 14:22:54 +0300366 return(1);
367 depth2++;
368 }
369 root = cur;
Xin Li28c53d32017-03-07 00:33:02 +0000370 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
371 if (cur->parent == node2)
Denis Pauke28c8a12013-08-03 14:22:54 +0300372 return(-1);
373 depth1++;
374 }
375 /*
376 * Distinct document (or distinct entities :-( ) case.
377 */
378 if (root != cur) {
379 return(-2);
380 }
381 /*
382 * get the nearest common ancestor.
383 */
384 while (depth1 > depth2) {
385 depth1--;
386 node1 = node1->parent;
387 }
388 while (depth2 > depth1) {
389 depth2--;
390 node2 = node2->parent;
391 }
392 while (node1->parent != node2->parent) {
393 node1 = node1->parent;
394 node2 = node2->parent;
395 /* should not happen but just in case ... */
396 if ((node1 == NULL) || (node2 == NULL))
397 return(-2);
398 }
399 /*
400 * Find who's first.
401 */
402 if (node1 == node2->prev)
403 return(1);
404 if (node1 == node2->next)
405 return(-1);
406 /*
407 * Speedup using document order if availble.
408 */
409 if ((node1->type == XML_ELEMENT_NODE) &&
410 (node2->type == XML_ELEMENT_NODE) &&
411 (0 > (long) node1->content) &&
412 (0 > (long) node2->content) &&
413 (node1->doc == node2->doc)) {
414
415 l1 = -((long) node1->content);
416 l2 = -((long) node2->content);
417 if (l1 < l2)
418 return(1);
419 if (l1 > l2)
420 return(-1);
421 }
422
423 for (cur = node1->next;cur != NULL;cur = cur->next)
424 if (cur == node2)
425 return(1);
426 return(-1); /* assume there is no sibling list corruption */
427}
428#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
429
Vojtech Fried3e031b72012-08-24 16:52:44 +0800430/*
431 * Wrapper for the Timsort argorithm from timsort.h
432 */
433#ifdef WITH_TIM_SORT
434#define SORT_NAME libxml_domnode
435#define SORT_TYPE xmlNodePtr
436/**
437 * wrap_cmp:
438 * @x: a node
439 * @y: another node
440 *
441 * Comparison function for the Timsort implementation
442 *
Daniel Veillard510e7582012-09-04 11:50:36 +0800443 * Returns -2 in case of error -1 if first point < second point, 0 if
444 * it's the same node, +1 otherwise
Vojtech Fried3e031b72012-08-24 16:52:44 +0800445 */
446static
447int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
448#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Vojtech Fried3e031b72012-08-24 16:52:44 +0800449 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
450 {
451 int res = xmlXPathCmpNodesExt(x, y);
452 return res == -2 ? res : -res;
453 }
454#else
455 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
456 {
457 int res = xmlXPathCmpNodes(x, y);
458 return res == -2 ? res : -res;
459 }
460#endif
461#define SORT_CMP(x, y) (wrap_cmp(x, y))
462#include "timsort.h"
463#endif /* WITH_TIM_SORT */
464
William M. Brack21e4ef22005-01-02 09:53:13 +0000465#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000466
467/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000468 * *
469 * Floating point stuff *
470 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000471 ************************************************************************/
472
Daniel Veillardc0631a62001-09-20 13:56:06 +0000473#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000474#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000475#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000476#include "trionan.c"
477
Owen Taylor3473f882001-02-23 17:55:21 +0000478/*
Owen Taylor3473f882001-02-23 17:55:21 +0000479 * The lack of portability of this section of the libc is annoying !
480 */
481double xmlXPathNAN = 0;
482double xmlXPathPINF = 1;
483double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000484static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000485static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000486
Owen Taylor3473f882001-02-23 17:55:21 +0000487/**
488 * xmlXPathInit:
489 *
490 * Initialize the XPath environment
491 */
492void
493xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000494 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000495
Bjorn Reese45029602001-08-21 09:23:53 +0000496 xmlXPathPINF = trio_pinf();
497 xmlXPathNINF = trio_ninf();
498 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000499 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000500
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000501 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000502}
503
Daniel Veillardcda96922001-08-21 10:56:31 +0000504/**
505 * xmlXPathIsNaN:
506 * @val: a double value
507 *
508 * Provides a portable isnan() function to detect whether a double
509 * is a NotaNumber. Based on trio code
510 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000511 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000512 * Returns 1 if the value is a NaN, 0 otherwise
513 */
514int
515xmlXPathIsNaN(double val) {
516 return(trio_isnan(val));
517}
518
519/**
520 * xmlXPathIsInf:
521 * @val: a double value
522 *
523 * Provides a portable isinf() function to detect whether a double
524 * is a +Infinite or -Infinite. Based on trio code
525 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000526 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000527 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
528 */
529int
530xmlXPathIsInf(double val) {
531 return(trio_isinf(val));
532}
533
Daniel Veillard4432df22003-09-28 18:58:27 +0000534#endif /* SCHEMAS or XPATH */
535#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000536/**
537 * xmlXPathGetSign:
538 * @val: a double value
539 *
540 * Provides a portable function to detect the sign of a double
541 * Modified from trio code
542 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000543 *
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000544 * Returns 1 if the value is Negative, 0 if positive
545 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000546static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000547xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000548 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000549}
550
551
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000552/*
553 * TODO: when compatibility allows remove all "fake node libxslt" strings
554 * the test should just be name[0] = ' '
555 */
Daniel Veillard074f37e2008-09-01 13:38:22 +0000556#ifdef DEBUG_XPATH_EXPRESSION
557#define DEBUG_STEP
558#define DEBUG_EXPR
559#define DEBUG_EVAL_COUNTS
560#endif
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000561
562static xmlNs xmlXPathXMLNamespaceStruct = {
563 NULL,
564 XML_NAMESPACE_DECL,
565 XML_XML_NAMESPACE,
566 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000567 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000568 NULL
569};
570static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
571#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard45490ae2008-07-29 09:13:19 +0000572/*
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000573 * Optimizer is disabled only when threaded apps are detected while
574 * the library ain't compiled for thread safety.
575 */
576static int xmlXPathDisableOptimizer = 0;
577#endif
578
Owen Taylor3473f882001-02-23 17:55:21 +0000579/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000580 * *
581 * Error handling routines *
582 * *
583 ************************************************************************/
584
Daniel Veillard24505b02005-07-28 23:49:35 +0000585/**
586 * XP_ERRORNULL:
587 * @X: the error code
588 *
589 * Macro to raise an XPath error and return NULL.
590 */
591#define XP_ERRORNULL(X) \
592 { xmlXPathErr(ctxt, X); return(NULL); }
593
William M. Brack08171912003-12-29 02:52:11 +0000594/*
595 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
596 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000597static const char *xmlXPathErrorMessages[] = {
598 "Ok\n",
599 "Number encoding\n",
600 "Unfinished literal\n",
601 "Start of literal\n",
602 "Expected $ for variable reference\n",
603 "Undefined variable\n",
604 "Invalid predicate\n",
605 "Invalid expression\n",
606 "Missing closing curly brace\n",
607 "Unregistered function\n",
608 "Invalid operand\n",
609 "Invalid type\n",
610 "Invalid number of arguments\n",
611 "Invalid context size\n",
612 "Invalid context position\n",
613 "Memory allocation error\n",
614 "Syntax error\n",
615 "Resource error\n",
616 "Sub resource error\n",
617 "Undefined namespace prefix\n",
618 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000619 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000620 "Invalid or incomplete context\n",
Jan Pokorný75801652013-12-19 15:09:14 +0100621 "Stack usage error\n",
Daniel Veillard47881282012-09-07 14:24:50 +0800622 "Forbidden variable\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000623 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000624};
William M. Brackcd65bc92005-01-06 09:39:18 +0000625#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
626 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000627/**
628 * xmlXPathErrMemory:
629 * @ctxt: an XPath context
630 * @extra: extra informations
631 *
632 * Handle a redefinition of attribute error
633 */
634static void
635xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
636{
637 if (ctxt != NULL) {
638 if (extra) {
639 xmlChar buf[200];
640
641 xmlStrPrintf(buf, 200,
Xin Li28c53d32017-03-07 00:33:02 +0000642 "Memory allocation failed : %s\n",
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000643 extra);
644 ctxt->lastError.message = (char *) xmlStrdup(buf);
645 } else {
646 ctxt->lastError.message = (char *)
647 xmlStrdup(BAD_CAST "Memory allocation failed\n");
648 }
649 ctxt->lastError.domain = XML_FROM_XPATH;
650 ctxt->lastError.code = XML_ERR_NO_MEMORY;
651 if (ctxt->error != NULL)
652 ctxt->error(ctxt->userData, &ctxt->lastError);
653 } else {
654 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000655 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000656 NULL, NULL, XML_FROM_XPATH,
657 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
658 extra, NULL, NULL, 0, 0,
659 "Memory allocation failed : %s\n", extra);
660 else
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 NULL, NULL, NULL, 0, 0,
665 "Memory allocation failed\n");
666 }
667}
668
669/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000670 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000671 * @ctxt: an XPath parser context
672 * @extra: extra informations
673 *
674 * Handle a redefinition of attribute error
675 */
676static void
677xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
678{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000679 if (ctxt == NULL)
680 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000681 else {
682 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000683 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000684 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000685}
686
687/**
688 * xmlXPathErr:
689 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000690 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000691 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000692 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000693 */
694void
695xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
696{
William M. Brackcd65bc92005-01-06 09:39:18 +0000697 if ((error < 0) || (error > MAXERRNO))
698 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000699 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000700 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000701 NULL, NULL, XML_FROM_XPATH,
702 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
703 XML_ERR_ERROR, NULL, 0,
704 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200705 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000706 return;
707 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000708 ctxt->error = error;
709 if (ctxt->context == NULL) {
710 __xmlRaiseError(NULL, NULL, NULL,
711 NULL, NULL, XML_FROM_XPATH,
712 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
713 XML_ERR_ERROR, NULL, 0,
714 (const char *) ctxt->base, NULL, NULL,
715 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200716 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000717 return;
718 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000719
720 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000721 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000722
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000723 ctxt->context->lastError.domain = XML_FROM_XPATH;
724 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
725 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000726 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000727 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
728 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
729 ctxt->context->lastError.node = ctxt->context->debugNode;
730 if (ctxt->context->error != NULL) {
731 ctxt->context->error(ctxt->context->userData,
732 &ctxt->context->lastError);
733 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000734 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000735 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
736 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
737 XML_ERR_ERROR, NULL, 0,
738 (const char *) ctxt->base, NULL, NULL,
739 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200740 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000741 }
742
743}
744
745/**
746 * xmlXPatherror:
747 * @ctxt: the XPath Parser context
748 * @file: the file name
749 * @line: the line number
750 * @no: the error number
751 *
752 * Formats an error message.
753 */
754void
755xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
756 int line ATTRIBUTE_UNUSED, int no) {
757 xmlXPathErr(ctxt, no);
758}
759
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000760/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000761 * *
762 * Utilities *
763 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000764 ************************************************************************/
765
766/**
767 * xsltPointerList:
768 *
769 * Pointer-list for various purposes.
770 */
771typedef struct _xmlPointerList xmlPointerList;
772typedef xmlPointerList *xmlPointerListPtr;
773struct _xmlPointerList {
774 void **items;
775 int number;
776 int size;
777};
778/*
779* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
780* and here, we should make the functions public.
781*/
782static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000783xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000784 void *item,
785 int initialSize)
786{
787 if (list->items == NULL) {
788 if (initialSize <= 0)
789 initialSize = 1;
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800790 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000791 if (list->items == NULL) {
792 xmlXPathErrMemory(NULL,
793 "xmlPointerListCreate: allocating item\n");
794 return(-1);
795 }
796 list->number = 0;
797 list->size = initialSize;
798 } else if (list->size <= list->number) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800799 if (list->size > 50000000) {
800 xmlXPathErrMemory(NULL,
801 "xmlPointerListAddSize: re-allocating item\n");
802 return(-1);
803 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000804 list->size *= 2;
805 list->items = (void **) xmlRealloc(list->items,
806 list->size * sizeof(void *));
807 if (list->items == NULL) {
808 xmlXPathErrMemory(NULL,
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800809 "xmlPointerListAddSize: re-allocating item\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000810 list->size = 0;
811 return(-1);
812 }
813 }
814 list->items[list->number++] = item;
815 return(0);
816}
817
818/**
819 * xsltPointerListCreate:
820 *
821 * Creates an xsltPointerList structure.
822 *
823 * Returns a xsltPointerList structure or NULL in case of an error.
824 */
825static xmlPointerListPtr
826xmlPointerListCreate(int initialSize)
827{
828 xmlPointerListPtr ret;
829
830 ret = xmlMalloc(sizeof(xmlPointerList));
831 if (ret == NULL) {
832 xmlXPathErrMemory(NULL,
833 "xmlPointerListCreate: allocating item\n");
834 return (NULL);
835 }
836 memset(ret, 0, sizeof(xmlPointerList));
837 if (initialSize > 0) {
838 xmlPointerListAddSize(ret, NULL, initialSize);
839 ret->number = 0;
840 }
841 return (ret);
842}
843
844/**
845 * xsltPointerListFree:
846 *
847 * Frees the xsltPointerList structure. This does not free
848 * the content of the list.
849 */
850static void
851xmlPointerListFree(xmlPointerListPtr list)
852{
853 if (list == NULL)
854 return;
855 if (list->items != NULL)
856 xmlFree(list->items);
857 xmlFree(list);
858}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000859
860/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000861 * *
862 * Parser Types *
863 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000864 ************************************************************************/
865
866/*
867 * Types are private:
868 */
869
870typedef enum {
871 XPATH_OP_END=0,
872 XPATH_OP_AND,
873 XPATH_OP_OR,
874 XPATH_OP_EQUAL,
875 XPATH_OP_CMP,
876 XPATH_OP_PLUS,
877 XPATH_OP_MULT,
878 XPATH_OP_UNION,
879 XPATH_OP_ROOT,
880 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000881 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000882 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000883 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000884 XPATH_OP_VARIABLE,
885 XPATH_OP_FUNCTION,
886 XPATH_OP_ARG,
887 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000888 XPATH_OP_FILTER, /* 17 */
889 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000890#ifdef LIBXML_XPTR_ENABLED
891 ,XPATH_OP_RANGETO
892#endif
893} xmlXPathOp;
894
895typedef enum {
896 AXIS_ANCESTOR = 1,
897 AXIS_ANCESTOR_OR_SELF,
898 AXIS_ATTRIBUTE,
899 AXIS_CHILD,
900 AXIS_DESCENDANT,
901 AXIS_DESCENDANT_OR_SELF,
902 AXIS_FOLLOWING,
903 AXIS_FOLLOWING_SIBLING,
904 AXIS_NAMESPACE,
905 AXIS_PARENT,
906 AXIS_PRECEDING,
907 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000908 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000909} xmlXPathAxisVal;
910
911typedef enum {
912 NODE_TEST_NONE = 0,
913 NODE_TEST_TYPE = 1,
914 NODE_TEST_PI = 2,
915 NODE_TEST_ALL = 3,
916 NODE_TEST_NS = 4,
917 NODE_TEST_NAME = 5
918} xmlXPathTestVal;
919
920typedef enum {
921 NODE_TYPE_NODE = 0,
922 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
923 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000924 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000925} xmlXPathTypeVal;
926
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000927typedef struct _xmlXPathStepOp xmlXPathStepOp;
928typedef xmlXPathStepOp *xmlXPathStepOpPtr;
929struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000930 xmlXPathOp op; /* The identifier of the operation */
931 int ch1; /* First child */
932 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000933 int value;
934 int value2;
935 int value3;
936 void *value4;
937 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000938 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000939 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000940};
941
942struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000943 int nbStep; /* Number of steps in this expression */
944 int maxStep; /* Maximum number of steps allocated */
945 xmlXPathStepOp *steps; /* ops for computation of this expression */
946 int last; /* index of last step in expression */
947 xmlChar *expr; /* the expression being computed */
Xin Li28c53d32017-03-07 00:33:02 +0000948 xmlDictPtr dict; /* the dictionary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000949#ifdef DEBUG_EVAL_COUNTS
950 int nb;
951 xmlChar *string;
952#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000953#ifdef XPATH_STREAMING
954 xmlPatternPtr stream;
955#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000956};
957
958/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000959 * *
960 * Forward declarations *
961 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000962 ************************************************************************/
963static void
964xmlXPathFreeValueTree(xmlNodeSetPtr obj);
965static void
966xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
967static int
968xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
969 xmlXPathStepOpPtr op, xmlNodePtr *first);
970static int
971xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000972 xmlXPathStepOpPtr op,
973 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000974
975/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000976 * *
977 * Parser Type functions *
978 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000979 ************************************************************************/
980
981/**
982 * xmlXPathNewCompExpr:
983 *
984 * Create a new Xpath component
985 *
986 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
987 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000988static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000989xmlXPathNewCompExpr(void) {
990 xmlXPathCompExprPtr cur;
991
992 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
993 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000994 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000995 return(NULL);
996 }
997 memset(cur, 0, sizeof(xmlXPathCompExpr));
998 cur->maxStep = 10;
999 cur->nbStep = 0;
1000 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1001 sizeof(xmlXPathStepOp));
1002 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001003 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001004 xmlFree(cur);
1005 return(NULL);
1006 }
1007 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1008 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +00001009#ifdef DEBUG_EVAL_COUNTS
1010 cur->nb = 0;
1011#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001012 return(cur);
1013}
1014
1015/**
1016 * xmlXPathFreeCompExpr:
1017 * @comp: an XPATH comp
1018 *
1019 * Free up the memory allocated by @comp
1020 */
1021void
Daniel Veillardf06307e2001-07-03 10:35:50 +00001022xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1023{
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001024 xmlXPathStepOpPtr op;
1025 int i;
1026
1027 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00001028 return;
Daniel Veillard4773df22004-01-23 13:15:13 +00001029 if (comp->dict == NULL) {
1030 for (i = 0; i < comp->nbStep; i++) {
1031 op = &comp->steps[i];
1032 if (op->value4 != NULL) {
1033 if (op->op == XPATH_OP_VALUE)
1034 xmlXPathFreeObject(op->value4);
1035 else
1036 xmlFree(op->value4);
1037 }
1038 if (op->value5 != NULL)
1039 xmlFree(op->value5);
1040 }
1041 } else {
1042 for (i = 0; i < comp->nbStep; i++) {
1043 op = &comp->steps[i];
1044 if (op->value4 != NULL) {
1045 if (op->op == XPATH_OP_VALUE)
1046 xmlXPathFreeObject(op->value4);
1047 }
1048 }
1049 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001050 }
1051 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00001052 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001053 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001054#ifdef DEBUG_EVAL_COUNTS
1055 if (comp->string != NULL) {
1056 xmlFree(comp->string);
1057 }
1058#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +00001059#ifdef XPATH_STREAMING
1060 if (comp->stream != NULL) {
1061 xmlFreePatternList(comp->stream);
1062 }
1063#endif
Daniel Veillard118aed72002-09-24 14:13:13 +00001064 if (comp->expr != NULL) {
1065 xmlFree(comp->expr);
1066 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00001067
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001068 xmlFree(comp);
1069}
1070
1071/**
1072 * xmlXPathCompExprAdd:
1073 * @comp: the compiled expression
1074 * @ch1: first child index
1075 * @ch2: second child index
1076 * @op: an op
1077 * @value: the first int value
1078 * @value2: the second int value
1079 * @value3: the third int value
1080 * @value4: the first string value
1081 * @value5: the second string value
1082 *
William M. Brack08171912003-12-29 02:52:11 +00001083 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001084 *
1085 * Returns -1 in case of failure, the index otherwise
1086 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001087static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001088xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1089 xmlXPathOp op, int value,
1090 int value2, int value3, void *value4, void *value5) {
1091 if (comp->nbStep >= comp->maxStep) {
1092 xmlXPathStepOp *real;
1093
Daniel Veillardcd852ad2012-07-30 10:12:18 +08001094 if (comp->maxStep >= XPATH_MAX_STEPS) {
1095 xmlXPathErrMemory(NULL, "adding step\n");
1096 return(-1);
1097 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001098 comp->maxStep *= 2;
1099 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1100 comp->maxStep * sizeof(xmlXPathStepOp));
1101 if (real == NULL) {
1102 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001103 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001104 return(-1);
1105 }
1106 comp->steps = real;
1107 }
1108 comp->last = comp->nbStep;
1109 comp->steps[comp->nbStep].ch1 = ch1;
1110 comp->steps[comp->nbStep].ch2 = ch2;
1111 comp->steps[comp->nbStep].op = op;
1112 comp->steps[comp->nbStep].value = value;
1113 comp->steps[comp->nbStep].value2 = value2;
1114 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +00001115 if ((comp->dict != NULL) &&
1116 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1117 (op == XPATH_OP_COLLECT))) {
1118 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001119 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001120 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001121 xmlFree(value4);
1122 } else
1123 comp->steps[comp->nbStep].value4 = NULL;
1124 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +00001125 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +00001126 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001127 xmlFree(value5);
1128 } else
1129 comp->steps[comp->nbStep].value5 = NULL;
1130 } else {
1131 comp->steps[comp->nbStep].value4 = value4;
1132 comp->steps[comp->nbStep].value5 = value5;
1133 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00001134 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001135 return(comp->nbStep++);
1136}
1137
Daniel Veillardf06307e2001-07-03 10:35:50 +00001138/**
1139 * xmlXPathCompSwap:
1140 * @comp: the compiled expression
1141 * @op: operation index
1142 *
1143 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +00001144 */
1145static void
1146xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1147 int tmp;
1148
Daniel Veillardbc6f7592002-04-16 07:49:59 +00001149#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +00001150 /*
1151 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +00001152 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +00001153 * application
1154 */
1155 if (xmlXPathDisableOptimizer)
1156 return;
1157#endif
1158
Daniel Veillardf06307e2001-07-03 10:35:50 +00001159 tmp = op->ch1;
1160 op->ch1 = op->ch2;
1161 op->ch2 = tmp;
1162}
1163
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001164#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1165 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1166 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001167#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1168 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1169 (op), (val), (val2), (val3), (val4), (val5))
1170
Daniel Veillard45490ae2008-07-29 09:13:19 +00001171#define PUSH_LEAVE_EXPR(op, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001172xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1173
Daniel Veillard45490ae2008-07-29 09:13:19 +00001174#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001175xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1176
Daniel Veillard45490ae2008-07-29 09:13:19 +00001177#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +00001178xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1179 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001180
1181/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +00001182 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001183 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001184 * *
1185 ************************************************************************/
1186
1187/* #define XP_DEFAULT_CACHE_ON */
1188
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001189#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001190
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001191typedef struct _xmlXPathContextCache xmlXPathContextCache;
1192typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1193struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00001194 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1195 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1196 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1197 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1198 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001199 int maxNodeset;
1200 int maxString;
1201 int maxBoolean;
1202 int maxNumber;
1203 int maxMisc;
1204#ifdef XP_DEBUG_OBJ_USAGE
1205 int dbgCachedAll;
1206 int dbgCachedNodeset;
1207 int dbgCachedString;
1208 int dbgCachedBool;
1209 int dbgCachedNumber;
1210 int dbgCachedPoint;
1211 int dbgCachedRange;
1212 int dbgCachedLocset;
1213 int dbgCachedUsers;
1214 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001215 int dbgCachedUndefined;
1216
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001217
1218 int dbgReusedAll;
1219 int dbgReusedNodeset;
1220 int dbgReusedString;
1221 int dbgReusedBool;
1222 int dbgReusedNumber;
1223 int dbgReusedPoint;
1224 int dbgReusedRange;
1225 int dbgReusedLocset;
1226 int dbgReusedUsers;
1227 int dbgReusedXSLTTree;
1228 int dbgReusedUndefined;
1229
1230#endif
1231};
1232
1233/************************************************************************
1234 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00001235 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +00001236 * *
1237 ************************************************************************/
1238
Daniel Veillard45490ae2008-07-29 09:13:19 +00001239#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +00001240 xmlGenericError(xmlGenericErrorContext, \
1241 "Internal error at %s:%d\n", \
1242 __FILE__, __LINE__);
1243
1244#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001245static void
1246xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001247 int i;
1248 char shift[100];
1249
1250 for (i = 0;((i < depth) && (i < 25));i++)
1251 shift[2 * i] = shift[2 * i + 1] = ' ';
1252 shift[2 * i] = shift[2 * i + 1] = 0;
1253 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001254 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001255 fprintf(output, "Node is NULL !\n");
1256 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001257
Owen Taylor3473f882001-02-23 17:55:21 +00001258 }
1259
1260 if ((cur->type == XML_DOCUMENT_NODE) ||
1261 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001262 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001263 fprintf(output, " /\n");
1264 } else if (cur->type == XML_ATTRIBUTE_NODE)
1265 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1266 else
1267 xmlDebugDumpOneNode(output, cur, depth);
1268}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001269static void
1270xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001271 xmlNodePtr tmp;
1272 int i;
1273 char shift[100];
1274
1275 for (i = 0;((i < depth) && (i < 25));i++)
1276 shift[2 * i] = shift[2 * i + 1] = ' ';
1277 shift[2 * i] = shift[2 * i + 1] = 0;
1278 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001279 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001280 fprintf(output, "Node is NULL !\n");
1281 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001282
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001283 }
1284
1285 while (cur != NULL) {
1286 tmp = cur;
1287 cur = cur->next;
1288 xmlDebugDumpOneNode(output, tmp, depth);
1289 }
1290}
Owen Taylor3473f882001-02-23 17:55:21 +00001291
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001292static void
1293xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001294 int i;
1295 char shift[100];
1296
1297 for (i = 0;((i < depth) && (i < 25));i++)
1298 shift[2 * i] = shift[2 * i + 1] = ' ';
1299 shift[2 * i] = shift[2 * i + 1] = 0;
1300
1301 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001302 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001303 fprintf(output, "NodeSet is NULL !\n");
1304 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001305
Owen Taylor3473f882001-02-23 17:55:21 +00001306 }
1307
Daniel Veillard911f49a2001-04-07 15:39:35 +00001308 if (cur != NULL) {
1309 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1310 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001311 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +00001312 fprintf(output, "%d", i + 1);
1313 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1314 }
Owen Taylor3473f882001-02-23 17:55:21 +00001315 }
1316}
1317
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001318static void
1319xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001320 int i;
1321 char shift[100];
1322
1323 for (i = 0;((i < depth) && (i < 25));i++)
1324 shift[2 * i] = shift[2 * i + 1] = ' ';
1325 shift[2 * i] = shift[2 * i + 1] = 0;
1326
1327 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001328 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001329 fprintf(output, "Value Tree is NULL !\n");
1330 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001331
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001332 }
1333
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001334 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001335 fprintf(output, "%d", i + 1);
1336 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1337}
Owen Taylor3473f882001-02-23 17:55:21 +00001338#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001339static void
1340xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001341 int i;
1342 char shift[100];
1343
1344 for (i = 0;((i < depth) && (i < 25));i++)
1345 shift[2 * i] = shift[2 * i + 1] = ' ';
1346 shift[2 * i] = shift[2 * i + 1] = 0;
1347
1348 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001349 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001350 fprintf(output, "LocationSet is NULL !\n");
1351 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001352
Owen Taylor3473f882001-02-23 17:55:21 +00001353 }
1354
1355 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001356 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001357 fprintf(output, "%d : ", i + 1);
1358 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1359 }
1360}
Daniel Veillard017b1082001-06-21 11:20:21 +00001361#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001362
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00001363/**
1364 * xmlXPathDebugDumpObject:
1365 * @output: the FILE * to dump the output
1366 * @cur: the object to inspect
1367 * @depth: indentation level
1368 *
1369 * Dump the content of the object for debugging purposes
1370 */
1371void
1372xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001373 int i;
1374 char shift[100];
1375
Daniel Veillarda82b1822004-11-08 16:24:57 +00001376 if (output == NULL) return;
1377
Owen Taylor3473f882001-02-23 17:55:21 +00001378 for (i = 0;((i < depth) && (i < 25));i++)
1379 shift[2 * i] = shift[2 * i + 1] = ' ';
1380 shift[2 * i] = shift[2 * i + 1] = 0;
1381
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001382
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001383 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001384
1385 if (cur == NULL) {
1386 fprintf(output, "Object is empty (NULL)\n");
1387 return;
1388 }
1389 switch(cur->type) {
1390 case XPATH_UNDEFINED:
1391 fprintf(output, "Object is uninitialized\n");
1392 break;
1393 case XPATH_NODESET:
1394 fprintf(output, "Object is a Node Set :\n");
1395 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1396 break;
1397 case XPATH_XSLT_TREE:
1398 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001399 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001400 break;
1401 case XPATH_BOOLEAN:
1402 fprintf(output, "Object is a Boolean : ");
1403 if (cur->boolval) fprintf(output, "true\n");
1404 else fprintf(output, "false\n");
1405 break;
1406 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001407 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001408 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001409 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001410 break;
1411 case -1:
1412 fprintf(output, "Object is a number : -Infinity\n");
1413 break;
1414 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001415 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001416 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001417 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1418 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001419 } else {
1420 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1421 }
1422 }
Owen Taylor3473f882001-02-23 17:55:21 +00001423 break;
1424 case XPATH_STRING:
1425 fprintf(output, "Object is a string : ");
1426 xmlDebugDumpString(output, cur->stringval);
1427 fprintf(output, "\n");
1428 break;
1429 case XPATH_POINT:
1430 fprintf(output, "Object is a point : index %d in node", cur->index);
1431 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1432 fprintf(output, "\n");
1433 break;
1434 case XPATH_RANGE:
1435 if ((cur->user2 == NULL) ||
1436 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1437 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001438 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001439 if (cur->index >= 0)
1440 fprintf(output, "index %d in ", cur->index);
1441 fprintf(output, "node\n");
1442 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1443 depth + 1);
1444 } else {
1445 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001446 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001447 fprintf(output, "From ");
1448 if (cur->index >= 0)
1449 fprintf(output, "index %d in ", cur->index);
1450 fprintf(output, "node\n");
1451 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1452 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001453 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001454 fprintf(output, "To ");
1455 if (cur->index2 >= 0)
1456 fprintf(output, "index %d in ", cur->index2);
1457 fprintf(output, "node\n");
1458 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1459 depth + 1);
1460 fprintf(output, "\n");
1461 }
1462 break;
1463 case XPATH_LOCATIONSET:
1464#if defined(LIBXML_XPTR_ENABLED)
1465 fprintf(output, "Object is a Location Set:\n");
1466 xmlXPathDebugDumpLocationSet(output,
1467 (xmlLocationSetPtr) cur->user, depth);
1468#endif
1469 break;
1470 case XPATH_USERS:
1471 fprintf(output, "Object is user defined\n");
1472 break;
1473 }
1474}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001475
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001476static void
1477xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001478 xmlXPathStepOpPtr op, int depth) {
1479 int i;
1480 char shift[100];
1481
1482 for (i = 0;((i < depth) && (i < 25));i++)
1483 shift[2 * i] = shift[2 * i + 1] = ' ';
1484 shift[2 * i] = shift[2 * i + 1] = 0;
1485
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001486 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001487 if (op == NULL) {
1488 fprintf(output, "Step is NULL\n");
1489 return;
1490 }
1491 switch (op->op) {
1492 case XPATH_OP_END:
1493 fprintf(output, "END"); break;
1494 case XPATH_OP_AND:
1495 fprintf(output, "AND"); break;
1496 case XPATH_OP_OR:
1497 fprintf(output, "OR"); break;
1498 case XPATH_OP_EQUAL:
1499 if (op->value)
1500 fprintf(output, "EQUAL =");
1501 else
1502 fprintf(output, "EQUAL !=");
1503 break;
1504 case XPATH_OP_CMP:
1505 if (op->value)
1506 fprintf(output, "CMP <");
1507 else
1508 fprintf(output, "CMP >");
1509 if (!op->value2)
1510 fprintf(output, "=");
1511 break;
1512 case XPATH_OP_PLUS:
1513 if (op->value == 0)
1514 fprintf(output, "PLUS -");
1515 else if (op->value == 1)
1516 fprintf(output, "PLUS +");
1517 else if (op->value == 2)
1518 fprintf(output, "PLUS unary -");
1519 else if (op->value == 3)
1520 fprintf(output, "PLUS unary - -");
1521 break;
1522 case XPATH_OP_MULT:
1523 if (op->value == 0)
1524 fprintf(output, "MULT *");
1525 else if (op->value == 1)
1526 fprintf(output, "MULT div");
1527 else
1528 fprintf(output, "MULT mod");
1529 break;
1530 case XPATH_OP_UNION:
1531 fprintf(output, "UNION"); break;
1532 case XPATH_OP_ROOT:
1533 fprintf(output, "ROOT"); break;
1534 case XPATH_OP_NODE:
1535 fprintf(output, "NODE"); break;
1536 case XPATH_OP_RESET:
1537 fprintf(output, "RESET"); break;
1538 case XPATH_OP_SORT:
1539 fprintf(output, "SORT"); break;
1540 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001541 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1542 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1543 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001544 const xmlChar *prefix = op->value4;
1545 const xmlChar *name = op->value5;
1546
1547 fprintf(output, "COLLECT ");
1548 switch (axis) {
1549 case AXIS_ANCESTOR:
1550 fprintf(output, " 'ancestors' "); break;
1551 case AXIS_ANCESTOR_OR_SELF:
1552 fprintf(output, " 'ancestors-or-self' "); break;
1553 case AXIS_ATTRIBUTE:
1554 fprintf(output, " 'attributes' "); break;
1555 case AXIS_CHILD:
1556 fprintf(output, " 'child' "); break;
1557 case AXIS_DESCENDANT:
1558 fprintf(output, " 'descendant' "); break;
1559 case AXIS_DESCENDANT_OR_SELF:
1560 fprintf(output, " 'descendant-or-self' "); break;
1561 case AXIS_FOLLOWING:
1562 fprintf(output, " 'following' "); break;
1563 case AXIS_FOLLOWING_SIBLING:
1564 fprintf(output, " 'following-siblings' "); break;
1565 case AXIS_NAMESPACE:
1566 fprintf(output, " 'namespace' "); break;
1567 case AXIS_PARENT:
1568 fprintf(output, " 'parent' "); break;
1569 case AXIS_PRECEDING:
1570 fprintf(output, " 'preceding' "); break;
1571 case AXIS_PRECEDING_SIBLING:
1572 fprintf(output, " 'preceding-sibling' "); break;
1573 case AXIS_SELF:
1574 fprintf(output, " 'self' "); break;
1575 }
1576 switch (test) {
1577 case NODE_TEST_NONE:
1578 fprintf(output, "'none' "); break;
1579 case NODE_TEST_TYPE:
1580 fprintf(output, "'type' "); break;
1581 case NODE_TEST_PI:
1582 fprintf(output, "'PI' "); break;
1583 case NODE_TEST_ALL:
1584 fprintf(output, "'all' "); break;
1585 case NODE_TEST_NS:
1586 fprintf(output, "'namespace' "); break;
1587 case NODE_TEST_NAME:
1588 fprintf(output, "'name' "); break;
1589 }
1590 switch (type) {
1591 case NODE_TYPE_NODE:
1592 fprintf(output, "'node' "); break;
1593 case NODE_TYPE_COMMENT:
1594 fprintf(output, "'comment' "); break;
1595 case NODE_TYPE_TEXT:
1596 fprintf(output, "'text' "); break;
1597 case NODE_TYPE_PI:
1598 fprintf(output, "'PI' "); break;
1599 }
1600 if (prefix != NULL)
1601 fprintf(output, "%s:", prefix);
1602 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001603 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001604 break;
1605
1606 }
1607 case XPATH_OP_VALUE: {
1608 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1609
1610 fprintf(output, "ELEM ");
1611 xmlXPathDebugDumpObject(output, object, 0);
1612 goto finish;
1613 }
1614 case XPATH_OP_VARIABLE: {
1615 const xmlChar *prefix = op->value5;
1616 const xmlChar *name = op->value4;
1617
1618 if (prefix != NULL)
1619 fprintf(output, "VARIABLE %s:%s", prefix, name);
1620 else
1621 fprintf(output, "VARIABLE %s", name);
1622 break;
1623 }
1624 case XPATH_OP_FUNCTION: {
1625 int nbargs = op->value;
1626 const xmlChar *prefix = op->value5;
1627 const xmlChar *name = op->value4;
1628
1629 if (prefix != NULL)
1630 fprintf(output, "FUNCTION %s:%s(%d args)",
1631 prefix, name, nbargs);
1632 else
1633 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1634 break;
1635 }
1636 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1637 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001638 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001639#ifdef LIBXML_XPTR_ENABLED
1640 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1641#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001642 default:
1643 fprintf(output, "UNKNOWN %d\n", op->op); return;
1644 }
1645 fprintf(output, "\n");
1646finish:
1647 if (op->ch1 >= 0)
1648 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1649 if (op->ch2 >= 0)
1650 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1651}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001652
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001653/**
1654 * xmlXPathDebugDumpCompExpr:
1655 * @output: the FILE * for the output
1656 * @comp: the precompiled XPath expression
1657 * @depth: the indentation level.
1658 *
1659 * Dumps the tree of the compiled XPath expression.
1660 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001661void
1662xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1663 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001664 int i;
1665 char shift[100];
1666
Daniel Veillarda82b1822004-11-08 16:24:57 +00001667 if ((output == NULL) || (comp == NULL)) return;
1668
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001669 for (i = 0;((i < depth) && (i < 25));i++)
1670 shift[2 * i] = shift[2 * i + 1] = ' ';
1671 shift[2 * i] = shift[2 * i + 1] = 0;
1672
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001673 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001674
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001675 fprintf(output, "Compiled Expression : %d elements\n",
1676 comp->nbStep);
1677 i = comp->last;
1678 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1679}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001680
1681#ifdef XP_DEBUG_OBJ_USAGE
1682
1683/*
1684* XPath object usage related debugging variables.
1685*/
1686static int xmlXPathDebugObjCounterUndefined = 0;
1687static int xmlXPathDebugObjCounterNodeset = 0;
1688static int xmlXPathDebugObjCounterBool = 0;
1689static int xmlXPathDebugObjCounterNumber = 0;
1690static int xmlXPathDebugObjCounterString = 0;
1691static int xmlXPathDebugObjCounterPoint = 0;
1692static int xmlXPathDebugObjCounterRange = 0;
1693static int xmlXPathDebugObjCounterLocset = 0;
1694static int xmlXPathDebugObjCounterUsers = 0;
1695static int xmlXPathDebugObjCounterXSLTTree = 0;
1696static int xmlXPathDebugObjCounterAll = 0;
1697
1698static int xmlXPathDebugObjTotalUndefined = 0;
1699static int xmlXPathDebugObjTotalNodeset = 0;
1700static int xmlXPathDebugObjTotalBool = 0;
1701static int xmlXPathDebugObjTotalNumber = 0;
1702static int xmlXPathDebugObjTotalString = 0;
1703static int xmlXPathDebugObjTotalPoint = 0;
1704static int xmlXPathDebugObjTotalRange = 0;
1705static int xmlXPathDebugObjTotalLocset = 0;
1706static int xmlXPathDebugObjTotalUsers = 0;
1707static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001708static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001709
1710static int xmlXPathDebugObjMaxUndefined = 0;
1711static int xmlXPathDebugObjMaxNodeset = 0;
1712static int xmlXPathDebugObjMaxBool = 0;
1713static int xmlXPathDebugObjMaxNumber = 0;
1714static int xmlXPathDebugObjMaxString = 0;
1715static int xmlXPathDebugObjMaxPoint = 0;
1716static int xmlXPathDebugObjMaxRange = 0;
1717static int xmlXPathDebugObjMaxLocset = 0;
1718static int xmlXPathDebugObjMaxUsers = 0;
1719static int xmlXPathDebugObjMaxXSLTTree = 0;
1720static int xmlXPathDebugObjMaxAll = 0;
1721
1722/* REVISIT TODO: Make this static when committing */
1723static void
1724xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1725{
1726 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001727 if (ctxt->cache != NULL) {
1728 xmlXPathContextCachePtr cache =
1729 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001730
1731 cache->dbgCachedAll = 0;
1732 cache->dbgCachedNodeset = 0;
1733 cache->dbgCachedString = 0;
1734 cache->dbgCachedBool = 0;
1735 cache->dbgCachedNumber = 0;
1736 cache->dbgCachedPoint = 0;
1737 cache->dbgCachedRange = 0;
1738 cache->dbgCachedLocset = 0;
1739 cache->dbgCachedUsers = 0;
1740 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001741 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001742
1743 cache->dbgReusedAll = 0;
1744 cache->dbgReusedNodeset = 0;
1745 cache->dbgReusedString = 0;
1746 cache->dbgReusedBool = 0;
1747 cache->dbgReusedNumber = 0;
1748 cache->dbgReusedPoint = 0;
1749 cache->dbgReusedRange = 0;
1750 cache->dbgReusedLocset = 0;
1751 cache->dbgReusedUsers = 0;
1752 cache->dbgReusedXSLTTree = 0;
1753 cache->dbgReusedUndefined = 0;
1754 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001755 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001756
1757 xmlXPathDebugObjCounterUndefined = 0;
1758 xmlXPathDebugObjCounterNodeset = 0;
1759 xmlXPathDebugObjCounterBool = 0;
1760 xmlXPathDebugObjCounterNumber = 0;
1761 xmlXPathDebugObjCounterString = 0;
1762 xmlXPathDebugObjCounterPoint = 0;
1763 xmlXPathDebugObjCounterRange = 0;
1764 xmlXPathDebugObjCounterLocset = 0;
1765 xmlXPathDebugObjCounterUsers = 0;
1766 xmlXPathDebugObjCounterXSLTTree = 0;
1767 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001768
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001769 xmlXPathDebugObjTotalUndefined = 0;
1770 xmlXPathDebugObjTotalNodeset = 0;
1771 xmlXPathDebugObjTotalBool = 0;
1772 xmlXPathDebugObjTotalNumber = 0;
1773 xmlXPathDebugObjTotalString = 0;
1774 xmlXPathDebugObjTotalPoint = 0;
1775 xmlXPathDebugObjTotalRange = 0;
1776 xmlXPathDebugObjTotalLocset = 0;
1777 xmlXPathDebugObjTotalUsers = 0;
1778 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001779 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001780
1781 xmlXPathDebugObjMaxUndefined = 0;
1782 xmlXPathDebugObjMaxNodeset = 0;
1783 xmlXPathDebugObjMaxBool = 0;
1784 xmlXPathDebugObjMaxNumber = 0;
1785 xmlXPathDebugObjMaxString = 0;
1786 xmlXPathDebugObjMaxPoint = 0;
1787 xmlXPathDebugObjMaxRange = 0;
1788 xmlXPathDebugObjMaxLocset = 0;
1789 xmlXPathDebugObjMaxUsers = 0;
1790 xmlXPathDebugObjMaxXSLTTree = 0;
1791 xmlXPathDebugObjMaxAll = 0;
1792
1793}
1794
1795static void
1796xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1797 xmlXPathObjectType objType)
1798{
1799 int isCached = 0;
1800
1801 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001802 if (ctxt->cache != NULL) {
1803 xmlXPathContextCachePtr cache =
1804 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001805
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001806 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001807
1808 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001809 switch (objType) {
1810 case XPATH_UNDEFINED:
1811 cache->dbgReusedUndefined++;
1812 break;
1813 case XPATH_NODESET:
1814 cache->dbgReusedNodeset++;
1815 break;
1816 case XPATH_BOOLEAN:
1817 cache->dbgReusedBool++;
1818 break;
1819 case XPATH_NUMBER:
1820 cache->dbgReusedNumber++;
1821 break;
1822 case XPATH_STRING:
1823 cache->dbgReusedString++;
1824 break;
1825 case XPATH_POINT:
1826 cache->dbgReusedPoint++;
1827 break;
1828 case XPATH_RANGE:
1829 cache->dbgReusedRange++;
1830 break;
1831 case XPATH_LOCATIONSET:
1832 cache->dbgReusedLocset++;
1833 break;
1834 case XPATH_USERS:
1835 cache->dbgReusedUsers++;
1836 break;
1837 case XPATH_XSLT_TREE:
1838 cache->dbgReusedXSLTTree++;
1839 break;
1840 default:
1841 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001842 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001843 }
1844 }
1845
1846 switch (objType) {
1847 case XPATH_UNDEFINED:
1848 if (! isCached)
1849 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001850 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001851 if (xmlXPathDebugObjCounterUndefined >
1852 xmlXPathDebugObjMaxUndefined)
1853 xmlXPathDebugObjMaxUndefined =
1854 xmlXPathDebugObjCounterUndefined;
1855 break;
1856 case XPATH_NODESET:
1857 if (! isCached)
1858 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001859 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001860 if (xmlXPathDebugObjCounterNodeset >
1861 xmlXPathDebugObjMaxNodeset)
1862 xmlXPathDebugObjMaxNodeset =
1863 xmlXPathDebugObjCounterNodeset;
1864 break;
1865 case XPATH_BOOLEAN:
1866 if (! isCached)
1867 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001868 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001869 if (xmlXPathDebugObjCounterBool >
1870 xmlXPathDebugObjMaxBool)
1871 xmlXPathDebugObjMaxBool =
1872 xmlXPathDebugObjCounterBool;
1873 break;
1874 case XPATH_NUMBER:
1875 if (! isCached)
1876 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001877 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001878 if (xmlXPathDebugObjCounterNumber >
1879 xmlXPathDebugObjMaxNumber)
1880 xmlXPathDebugObjMaxNumber =
1881 xmlXPathDebugObjCounterNumber;
1882 break;
1883 case XPATH_STRING:
1884 if (! isCached)
1885 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001886 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001887 if (xmlXPathDebugObjCounterString >
1888 xmlXPathDebugObjMaxString)
1889 xmlXPathDebugObjMaxString =
1890 xmlXPathDebugObjCounterString;
1891 break;
1892 case XPATH_POINT:
1893 if (! isCached)
1894 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001895 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001896 if (xmlXPathDebugObjCounterPoint >
1897 xmlXPathDebugObjMaxPoint)
1898 xmlXPathDebugObjMaxPoint =
1899 xmlXPathDebugObjCounterPoint;
1900 break;
1901 case XPATH_RANGE:
1902 if (! isCached)
1903 xmlXPathDebugObjTotalRange++;
1904 xmlXPathDebugObjCounterRange++;
1905 if (xmlXPathDebugObjCounterRange >
1906 xmlXPathDebugObjMaxRange)
1907 xmlXPathDebugObjMaxRange =
1908 xmlXPathDebugObjCounterRange;
1909 break;
1910 case XPATH_LOCATIONSET:
1911 if (! isCached)
1912 xmlXPathDebugObjTotalLocset++;
1913 xmlXPathDebugObjCounterLocset++;
1914 if (xmlXPathDebugObjCounterLocset >
1915 xmlXPathDebugObjMaxLocset)
1916 xmlXPathDebugObjMaxLocset =
1917 xmlXPathDebugObjCounterLocset;
1918 break;
1919 case XPATH_USERS:
1920 if (! isCached)
1921 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001922 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001923 if (xmlXPathDebugObjCounterUsers >
1924 xmlXPathDebugObjMaxUsers)
1925 xmlXPathDebugObjMaxUsers =
1926 xmlXPathDebugObjCounterUsers;
1927 break;
1928 case XPATH_XSLT_TREE:
1929 if (! isCached)
1930 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001931 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001932 if (xmlXPathDebugObjCounterXSLTTree >
1933 xmlXPathDebugObjMaxXSLTTree)
1934 xmlXPathDebugObjMaxXSLTTree =
1935 xmlXPathDebugObjCounterXSLTTree;
1936 break;
1937 default:
1938 break;
1939 }
1940 if (! isCached)
1941 xmlXPathDebugObjTotalAll++;
1942 xmlXPathDebugObjCounterAll++;
1943 if (xmlXPathDebugObjCounterAll >
1944 xmlXPathDebugObjMaxAll)
1945 xmlXPathDebugObjMaxAll =
1946 xmlXPathDebugObjCounterAll;
1947}
1948
1949static void
1950xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1951 xmlXPathObjectType objType)
1952{
1953 int isCached = 0;
1954
1955 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001956 if (ctxt->cache != NULL) {
1957 xmlXPathContextCachePtr cache =
1958 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001959
Daniel Veillard45490ae2008-07-29 09:13:19 +00001960 isCached = 1;
1961
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001962 cache->dbgCachedAll++;
1963 switch (objType) {
1964 case XPATH_UNDEFINED:
1965 cache->dbgCachedUndefined++;
1966 break;
1967 case XPATH_NODESET:
1968 cache->dbgCachedNodeset++;
1969 break;
1970 case XPATH_BOOLEAN:
1971 cache->dbgCachedBool++;
1972 break;
1973 case XPATH_NUMBER:
1974 cache->dbgCachedNumber++;
1975 break;
1976 case XPATH_STRING:
1977 cache->dbgCachedString++;
1978 break;
1979 case XPATH_POINT:
1980 cache->dbgCachedPoint++;
1981 break;
1982 case XPATH_RANGE:
1983 cache->dbgCachedRange++;
1984 break;
1985 case XPATH_LOCATIONSET:
1986 cache->dbgCachedLocset++;
1987 break;
1988 case XPATH_USERS:
1989 cache->dbgCachedUsers++;
1990 break;
1991 case XPATH_XSLT_TREE:
1992 cache->dbgCachedXSLTTree++;
1993 break;
1994 default:
1995 break;
1996 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001997
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001998 }
1999 }
2000 switch (objType) {
2001 case XPATH_UNDEFINED:
2002 xmlXPathDebugObjCounterUndefined--;
2003 break;
2004 case XPATH_NODESET:
2005 xmlXPathDebugObjCounterNodeset--;
2006 break;
2007 case XPATH_BOOLEAN:
2008 xmlXPathDebugObjCounterBool--;
2009 break;
2010 case XPATH_NUMBER:
2011 xmlXPathDebugObjCounterNumber--;
2012 break;
2013 case XPATH_STRING:
2014 xmlXPathDebugObjCounterString--;
2015 break;
2016 case XPATH_POINT:
2017 xmlXPathDebugObjCounterPoint--;
2018 break;
2019 case XPATH_RANGE:
2020 xmlXPathDebugObjCounterRange--;
2021 break;
2022 case XPATH_LOCATIONSET:
2023 xmlXPathDebugObjCounterLocset--;
2024 break;
2025 case XPATH_USERS:
2026 xmlXPathDebugObjCounterUsers--;
2027 break;
2028 case XPATH_XSLT_TREE:
2029 xmlXPathDebugObjCounterXSLTTree--;
2030 break;
2031 default:
2032 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002033 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002034 xmlXPathDebugObjCounterAll--;
2035}
2036
2037/* REVISIT TODO: Make this static when committing */
2038static void
2039xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2040{
2041 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2042 reqXSLTTree, reqUndefined;
2043 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2044 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2045 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2046 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2047 int leftObjs = xmlXPathDebugObjCounterAll;
2048
2049 reqAll = xmlXPathDebugObjTotalAll;
2050 reqNodeset = xmlXPathDebugObjTotalNodeset;
2051 reqString = xmlXPathDebugObjTotalString;
2052 reqBool = xmlXPathDebugObjTotalBool;
2053 reqNumber = xmlXPathDebugObjTotalNumber;
2054 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2055 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002056
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002057 printf("# XPath object usage:\n");
2058
2059 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002060 if (ctxt->cache != NULL) {
2061 xmlXPathContextCachePtr cache =
2062 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002063
2064 reAll = cache->dbgReusedAll;
2065 reqAll += reAll;
2066 reNodeset = cache->dbgReusedNodeset;
2067 reqNodeset += reNodeset;
2068 reString = cache->dbgReusedString;
2069 reqString += reString;
2070 reBool = cache->dbgReusedBool;
2071 reqBool += reBool;
2072 reNumber = cache->dbgReusedNumber;
2073 reqNumber += reNumber;
2074 reXSLTTree = cache->dbgReusedXSLTTree;
2075 reqXSLTTree += reXSLTTree;
2076 reUndefined = cache->dbgReusedUndefined;
2077 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002078
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002079 caAll = cache->dbgCachedAll;
2080 caBool = cache->dbgCachedBool;
2081 caNodeset = cache->dbgCachedNodeset;
2082 caString = cache->dbgCachedString;
2083 caNumber = cache->dbgCachedNumber;
2084 caXSLTTree = cache->dbgCachedXSLTTree;
2085 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002086
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002087 if (cache->nodesetObjs)
2088 leftObjs -= cache->nodesetObjs->number;
2089 if (cache->stringObjs)
2090 leftObjs -= cache->stringObjs->number;
2091 if (cache->booleanObjs)
2092 leftObjs -= cache->booleanObjs->number;
2093 if (cache->numberObjs)
2094 leftObjs -= cache->numberObjs->number;
2095 if (cache->miscObjs)
2096 leftObjs -= cache->miscObjs->number;
2097 }
2098 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002099
2100 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002101 printf("# total : %d\n", reqAll);
2102 printf("# left : %d\n", leftObjs);
2103 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2104 printf("# reused : %d\n", reAll);
2105 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2106
2107 printf("# node-sets\n");
2108 printf("# total : %d\n", reqNodeset);
2109 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2110 printf("# reused : %d\n", reNodeset);
2111 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2112
2113 printf("# strings\n");
2114 printf("# total : %d\n", reqString);
2115 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2116 printf("# reused : %d\n", reString);
2117 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2118
2119 printf("# booleans\n");
2120 printf("# total : %d\n", reqBool);
2121 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2122 printf("# reused : %d\n", reBool);
2123 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2124
2125 printf("# numbers\n");
2126 printf("# total : %d\n", reqNumber);
2127 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2128 printf("# reused : %d\n", reNumber);
2129 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2130
2131 printf("# XSLT result tree fragments\n");
2132 printf("# total : %d\n", reqXSLTTree);
2133 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2134 printf("# reused : %d\n", reXSLTTree);
2135 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2136
2137 printf("# undefined\n");
2138 printf("# total : %d\n", reqUndefined);
2139 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2140 printf("# reused : %d\n", reUndefined);
2141 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2142
2143}
2144
2145#endif /* XP_DEBUG_OBJ_USAGE */
2146
Daniel Veillard017b1082001-06-21 11:20:21 +00002147#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002148
2149/************************************************************************
2150 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002151 * XPath object caching *
2152 * *
2153 ************************************************************************/
2154
2155/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002156 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002157 *
2158 * Create a new object cache
2159 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002160 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002161 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002162static xmlXPathContextCachePtr
2163xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002164{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002165 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002166
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002167 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002168 if (ret == NULL) {
2169 xmlXPathErrMemory(NULL, "creating object cache\n");
2170 return(NULL);
2171 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002172 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002173 ret->maxNodeset = 100;
2174 ret->maxString = 100;
2175 ret->maxBoolean = 100;
2176 ret->maxNumber = 100;
2177 ret->maxMisc = 100;
2178 return(ret);
2179}
2180
2181static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002182xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002183{
2184 int i;
2185 xmlXPathObjectPtr obj;
2186
2187 if (list == NULL)
2188 return;
2189
2190 for (i = 0; i < list->number; i++) {
2191 obj = list->items[i];
2192 /*
2193 * Note that it is already assured that we don't need to
2194 * look out for namespace nodes in the node-set.
2195 */
2196 if (obj->nodesetval != NULL) {
2197 if (obj->nodesetval->nodeTab != NULL)
2198 xmlFree(obj->nodesetval->nodeTab);
2199 xmlFree(obj->nodesetval);
2200 }
2201 xmlFree(obj);
2202#ifdef XP_DEBUG_OBJ_USAGE
2203 xmlXPathDebugObjCounterAll--;
2204#endif
2205 }
2206 xmlPointerListFree(list);
2207}
2208
2209static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002210xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002211{
2212 if (cache == NULL)
2213 return;
2214 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002215 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002216 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002217 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002218 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002219 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002220 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002221 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002222 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002223 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002224 xmlFree(cache);
2225}
2226
2227/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002228 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002229 *
2230 * @ctxt: the XPath context
2231 * @active: enables/disables (creates/frees) the cache
Daniel Veillard45490ae2008-07-29 09:13:19 +00002232 * @value: a value with semantics dependant on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002233 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002234 *
2235 * Creates/frees an object cache on the XPath context.
2236 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002237 * to be reused.
2238 * @options:
2239 * 0: This will set the XPath object caching:
2240 * @value:
2241 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002242 * to be cached per slot
2243 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002244 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002245 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002246 *
2247 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2248 */
2249int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002250xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2251 int active,
2252 int value,
2253 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002254{
2255 if (ctxt == NULL)
2256 return(-1);
2257 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002258 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002259
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002260 if (ctxt->cache == NULL) {
2261 ctxt->cache = xmlXPathNewCache();
2262 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002263 return(-1);
2264 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002265 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002266 if (options == 0) {
2267 if (value < 0)
2268 value = 100;
2269 cache->maxNodeset = value;
2270 cache->maxString = value;
2271 cache->maxNumber = value;
2272 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00002273 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002274 }
2275 } else if (ctxt->cache != NULL) {
2276 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2277 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002278 }
2279 return(0);
2280}
2281
2282/**
2283 * xmlXPathCacheWrapNodeSet:
2284 * @ctxt: the XPath context
2285 * @val: the NodePtr value
2286 *
2287 * This is the cached version of xmlXPathWrapNodeSet().
2288 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2289 *
2290 * Returns the created or reused object.
2291 */
2292static xmlXPathObjectPtr
2293xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002294{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002295 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2296 xmlXPathContextCachePtr cache =
2297 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002298
2299 if ((cache->miscObjs != NULL) &&
2300 (cache->miscObjs->number != 0))
2301 {
2302 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002303
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002304 ret = (xmlXPathObjectPtr)
2305 cache->miscObjs->items[--cache->miscObjs->number];
2306 ret->type = XPATH_NODESET;
2307 ret->nodesetval = val;
2308#ifdef XP_DEBUG_OBJ_USAGE
2309 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2310#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00002311 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002312 }
2313 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002314
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002315 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00002316
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002317}
2318
2319/**
2320 * xmlXPathCacheWrapString:
2321 * @ctxt: the XPath context
2322 * @val: the xmlChar * value
2323 *
2324 * This is the cached version of xmlXPathWrapString().
2325 * Wraps the @val string into an XPath object.
2326 *
2327 * Returns the created or reused object.
2328 */
2329static xmlXPathObjectPtr
2330xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002331{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002332 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2333 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002334
2335 if ((cache->stringObjs != NULL) &&
2336 (cache->stringObjs->number != 0))
2337 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002338
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002339 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002340
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002341 ret = (xmlXPathObjectPtr)
2342 cache->stringObjs->items[--cache->stringObjs->number];
2343 ret->type = XPATH_STRING;
2344 ret->stringval = val;
2345#ifdef XP_DEBUG_OBJ_USAGE
2346 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2347#endif
2348 return(ret);
2349 } else if ((cache->miscObjs != NULL) &&
2350 (cache->miscObjs->number != 0))
2351 {
2352 xmlXPathObjectPtr ret;
2353 /*
2354 * Fallback to misc-cache.
2355 */
2356 ret = (xmlXPathObjectPtr)
2357 cache->miscObjs->items[--cache->miscObjs->number];
2358
2359 ret->type = XPATH_STRING;
2360 ret->stringval = val;
2361#ifdef XP_DEBUG_OBJ_USAGE
2362 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2363#endif
2364 return(ret);
2365 }
2366 }
2367 return(xmlXPathWrapString(val));
2368}
2369
2370/**
2371 * xmlXPathCacheNewNodeSet:
2372 * @ctxt: the XPath context
2373 * @val: the NodePtr value
2374 *
2375 * This is the cached version of xmlXPathNewNodeSet().
2376 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2377 * it with the single Node @val
2378 *
2379 * Returns the created or reused object.
2380 */
2381static xmlXPathObjectPtr
2382xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2383{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002384 if ((ctxt != NULL) && (ctxt->cache)) {
2385 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002386
2387 if ((cache->nodesetObjs != NULL) &&
2388 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002389 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002390 xmlXPathObjectPtr ret;
2391 /*
2392 * Use the nodset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002393 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002394 ret = (xmlXPathObjectPtr)
2395 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2396 ret->type = XPATH_NODESET;
2397 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002398 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002399 if ((ret->nodesetval->nodeMax == 0) ||
2400 (val->type == XML_NAMESPACE_DECL))
2401 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002402 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002403 } else {
2404 ret->nodesetval->nodeTab[0] = val;
2405 ret->nodesetval->nodeNr = 1;
2406 }
2407 }
2408#ifdef XP_DEBUG_OBJ_USAGE
2409 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2410#endif
2411 return(ret);
2412 } else if ((cache->miscObjs != NULL) &&
2413 (cache->miscObjs->number != 0))
2414 {
2415 xmlXPathObjectPtr ret;
2416 /*
2417 * Fallback to misc-cache.
2418 */
2419
2420 ret = (xmlXPathObjectPtr)
2421 cache->miscObjs->items[--cache->miscObjs->number];
2422
2423 ret->type = XPATH_NODESET;
2424 ret->boolval = 0;
2425 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08002426 if (ret->nodesetval == NULL) {
2427 ctxt->lastError.domain = XML_FROM_XPATH;
2428 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2429 return(NULL);
2430 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002431#ifdef XP_DEBUG_OBJ_USAGE
2432 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2433#endif
2434 return(ret);
2435 }
2436 }
2437 return(xmlXPathNewNodeSet(val));
2438}
2439
2440/**
2441 * xmlXPathCacheNewCString:
2442 * @ctxt: the XPath context
2443 * @val: the char * value
2444 *
2445 * This is the cached version of xmlXPathNewCString().
2446 * Acquire an xmlXPathObjectPtr of type string and of value @val
2447 *
2448 * Returns the created or reused object.
2449 */
2450static xmlXPathObjectPtr
2451xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002452{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002453 if ((ctxt != NULL) && (ctxt->cache)) {
2454 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002455
2456 if ((cache->stringObjs != NULL) &&
2457 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002458 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002459 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002460
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002461 ret = (xmlXPathObjectPtr)
2462 cache->stringObjs->items[--cache->stringObjs->number];
2463
2464 ret->type = XPATH_STRING;
2465 ret->stringval = xmlStrdup(BAD_CAST val);
2466#ifdef XP_DEBUG_OBJ_USAGE
2467 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2468#endif
2469 return(ret);
2470 } else if ((cache->miscObjs != NULL) &&
2471 (cache->miscObjs->number != 0))
2472 {
2473 xmlXPathObjectPtr ret;
2474
2475 ret = (xmlXPathObjectPtr)
2476 cache->miscObjs->items[--cache->miscObjs->number];
2477
2478 ret->type = XPATH_STRING;
2479 ret->stringval = xmlStrdup(BAD_CAST val);
2480#ifdef XP_DEBUG_OBJ_USAGE
2481 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2482#endif
2483 return(ret);
2484 }
2485 }
2486 return(xmlXPathNewCString(val));
2487}
2488
2489/**
2490 * xmlXPathCacheNewString:
2491 * @ctxt: the XPath context
2492 * @val: the xmlChar * value
2493 *
2494 * This is the cached version of xmlXPathNewString().
2495 * Acquire an xmlXPathObjectPtr of type string and of value @val
2496 *
2497 * Returns the created or reused object.
2498 */
2499static xmlXPathObjectPtr
2500xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002501{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002502 if ((ctxt != NULL) && (ctxt->cache)) {
2503 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002504
2505 if ((cache->stringObjs != NULL) &&
2506 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002507 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002508 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002509
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002510 ret = (xmlXPathObjectPtr)
2511 cache->stringObjs->items[--cache->stringObjs->number];
2512 ret->type = XPATH_STRING;
2513 if (val != NULL)
2514 ret->stringval = xmlStrdup(val);
2515 else
2516 ret->stringval = xmlStrdup((const xmlChar *)"");
2517#ifdef XP_DEBUG_OBJ_USAGE
2518 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2519#endif
2520 return(ret);
2521 } else if ((cache->miscObjs != NULL) &&
2522 (cache->miscObjs->number != 0))
2523 {
2524 xmlXPathObjectPtr ret;
2525
2526 ret = (xmlXPathObjectPtr)
2527 cache->miscObjs->items[--cache->miscObjs->number];
2528
2529 ret->type = XPATH_STRING;
2530 if (val != NULL)
2531 ret->stringval = xmlStrdup(val);
2532 else
2533 ret->stringval = xmlStrdup((const xmlChar *)"");
2534#ifdef XP_DEBUG_OBJ_USAGE
2535 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2536#endif
2537 return(ret);
2538 }
2539 }
2540 return(xmlXPathNewString(val));
2541}
2542
2543/**
2544 * xmlXPathCacheNewBoolean:
2545 * @ctxt: the XPath context
2546 * @val: the boolean value
2547 *
2548 * This is the cached version of xmlXPathNewBoolean().
2549 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2550 *
2551 * Returns the created or reused object.
2552 */
2553static xmlXPathObjectPtr
2554xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002555{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002556 if ((ctxt != NULL) && (ctxt->cache)) {
2557 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002558
2559 if ((cache->booleanObjs != NULL) &&
2560 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002561 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002562 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002563
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002564 ret = (xmlXPathObjectPtr)
2565 cache->booleanObjs->items[--cache->booleanObjs->number];
2566 ret->type = XPATH_BOOLEAN;
2567 ret->boolval = (val != 0);
2568#ifdef XP_DEBUG_OBJ_USAGE
2569 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2570#endif
2571 return(ret);
2572 } else if ((cache->miscObjs != NULL) &&
2573 (cache->miscObjs->number != 0))
2574 {
2575 xmlXPathObjectPtr ret;
2576
2577 ret = (xmlXPathObjectPtr)
2578 cache->miscObjs->items[--cache->miscObjs->number];
2579
2580 ret->type = XPATH_BOOLEAN;
2581 ret->boolval = (val != 0);
2582#ifdef XP_DEBUG_OBJ_USAGE
2583 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2584#endif
2585 return(ret);
2586 }
2587 }
2588 return(xmlXPathNewBoolean(val));
2589}
2590
2591/**
2592 * xmlXPathCacheNewFloat:
2593 * @ctxt: the XPath context
2594 * @val: the double value
2595 *
2596 * This is the cached version of xmlXPathNewFloat().
2597 * Acquires an xmlXPathObjectPtr of type double and of value @val
2598 *
2599 * Returns the created or reused object.
2600 */
2601static xmlXPathObjectPtr
2602xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2603{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002604 if ((ctxt != NULL) && (ctxt->cache)) {
2605 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002606
2607 if ((cache->numberObjs != NULL) &&
2608 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002609 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002610 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002611
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002612 ret = (xmlXPathObjectPtr)
2613 cache->numberObjs->items[--cache->numberObjs->number];
2614 ret->type = XPATH_NUMBER;
2615 ret->floatval = val;
2616#ifdef XP_DEBUG_OBJ_USAGE
2617 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2618#endif
2619 return(ret);
2620 } else if ((cache->miscObjs != NULL) &&
2621 (cache->miscObjs->number != 0))
2622 {
2623 xmlXPathObjectPtr ret;
2624
2625 ret = (xmlXPathObjectPtr)
2626 cache->miscObjs->items[--cache->miscObjs->number];
2627
2628 ret->type = XPATH_NUMBER;
2629 ret->floatval = val;
2630#ifdef XP_DEBUG_OBJ_USAGE
2631 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2632#endif
2633 return(ret);
2634 }
2635 }
2636 return(xmlXPathNewFloat(val));
2637}
2638
2639/**
2640 * xmlXPathCacheConvertString:
2641 * @ctxt: the XPath context
2642 * @val: an XPath object
2643 *
2644 * This is the cached version of xmlXPathConvertString().
2645 * Converts an existing object to its string() equivalent
2646 *
2647 * Returns a created or reused object, the old one is freed (cached)
2648 * (or the operation is done directly on @val)
2649 */
2650
2651static xmlXPathObjectPtr
2652xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002653 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002654
2655 if (val == NULL)
2656 return(xmlXPathCacheNewCString(ctxt, ""));
2657
2658 switch (val->type) {
2659 case XPATH_UNDEFINED:
2660#ifdef DEBUG_EXPR
2661 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2662#endif
2663 break;
2664 case XPATH_NODESET:
2665 case XPATH_XSLT_TREE:
2666 res = xmlXPathCastNodeSetToString(val->nodesetval);
2667 break;
2668 case XPATH_STRING:
2669 return(val);
2670 case XPATH_BOOLEAN:
2671 res = xmlXPathCastBooleanToString(val->boolval);
2672 break;
2673 case XPATH_NUMBER:
2674 res = xmlXPathCastNumberToString(val->floatval);
2675 break;
2676 case XPATH_USERS:
2677 case XPATH_POINT:
2678 case XPATH_RANGE:
2679 case XPATH_LOCATIONSET:
2680 TODO;
2681 break;
2682 }
2683 xmlXPathReleaseObject(ctxt, val);
2684 if (res == NULL)
2685 return(xmlXPathCacheNewCString(ctxt, ""));
2686 return(xmlXPathCacheWrapString(ctxt, res));
2687}
2688
2689/**
2690 * xmlXPathCacheObjectCopy:
2691 * @ctxt: the XPath context
2692 * @val: the original object
2693 *
2694 * This is the cached version of xmlXPathObjectCopy().
2695 * Acquire a copy of a given object
2696 *
2697 * Returns a created or reused created object.
2698 */
2699static xmlXPathObjectPtr
2700xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2701{
2702 if (val == NULL)
2703 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002704
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002705 if (XP_HAS_CACHE(ctxt)) {
2706 switch (val->type) {
2707 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002708 return(xmlXPathCacheWrapNodeSet(ctxt,
2709 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002710 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002711 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002712 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002713 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002714 case XPATH_NUMBER:
2715 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2716 default:
2717 break;
2718 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002719 }
2720 return(xmlXPathObjectCopy(val));
2721}
2722
2723/**
2724 * xmlXPathCacheConvertBoolean:
2725 * @ctxt: the XPath context
2726 * @val: an XPath object
2727 *
2728 * This is the cached version of xmlXPathConvertBoolean().
2729 * Converts an existing object to its boolean() equivalent
2730 *
2731 * Returns a created or reused object, the old one is freed (or the operation
2732 * is done directly on @val)
2733 */
2734static xmlXPathObjectPtr
2735xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2736 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002737
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002738 if (val == NULL)
2739 return(xmlXPathCacheNewBoolean(ctxt, 0));
2740 if (val->type == XPATH_BOOLEAN)
2741 return(val);
2742 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2743 xmlXPathReleaseObject(ctxt, val);
2744 return(ret);
2745}
2746
2747/**
2748 * xmlXPathCacheConvertNumber:
2749 * @ctxt: the XPath context
2750 * @val: an XPath object
2751 *
2752 * This is the cached version of xmlXPathConvertNumber().
2753 * Converts an existing object to its number() equivalent
2754 *
2755 * Returns a created or reused object, the old one is freed (or the operation
2756 * is done directly on @val)
2757 */
2758static xmlXPathObjectPtr
2759xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2760 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002761
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002762 if (val == NULL)
2763 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2764 if (val->type == XPATH_NUMBER)
2765 return(val);
2766 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2767 xmlXPathReleaseObject(ctxt, val);
2768 return(ret);
2769}
2770
2771/************************************************************************
2772 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002773 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002774 * *
2775 ************************************************************************/
2776
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002777/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002778 * xmlXPathSetFrame:
2779 * @ctxt: an XPath parser context
2780 *
2781 * Set the callee evaluation frame
2782 *
2783 * Returns the previous frame value to be restored once done
2784 */
2785static int
2786xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2787 int ret;
2788
2789 if (ctxt == NULL)
2790 return(0);
2791 ret = ctxt->valueFrame;
2792 ctxt->valueFrame = ctxt->valueNr;
2793 return(ret);
2794}
2795
2796/**
2797 * xmlXPathPopFrame:
2798 * @ctxt: an XPath parser context
2799 * @frame: the previous frame value
2800 *
2801 * Remove the callee evaluation frame
2802 */
2803static void
2804xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2805 if (ctxt == NULL)
2806 return;
2807 if (ctxt->valueNr < ctxt->valueFrame) {
2808 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2809 }
2810 ctxt->valueFrame = frame;
2811}
2812
2813/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002814 * valuePop:
2815 * @ctxt: an XPath evaluation context
2816 *
2817 * Pops the top XPath object from the value stack
2818 *
2819 * Returns the XPath object just removed
2820 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002821xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002822valuePop(xmlXPathParserContextPtr ctxt)
2823{
2824 xmlXPathObjectPtr ret;
2825
Daniel Veillarda82b1822004-11-08 16:24:57 +00002826 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002827 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002828
2829 if (ctxt->valueNr <= ctxt->valueFrame) {
2830 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2831 return (NULL);
2832 }
2833
Daniel Veillard1c732d22002-11-30 11:22:59 +00002834 ctxt->valueNr--;
2835 if (ctxt->valueNr > 0)
2836 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2837 else
2838 ctxt->value = NULL;
2839 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002840 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002841 return (ret);
2842}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002843/**
2844 * valuePush:
2845 * @ctxt: an XPath evaluation context
2846 * @value: the XPath object
2847 *
2848 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002849 *
2850 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002851 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002852int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002853valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2854{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002855 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002856 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002857 xmlXPathObjectPtr *tmp;
2858
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002859 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2860 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2861 ctxt->error = XPATH_MEMORY_ERROR;
2862 return (0);
2863 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002864 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2865 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002866 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002867 if (tmp == NULL) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002868 xmlXPathErrMemory(NULL, "pushing value\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08002869 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002870 return (0);
2871 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002872 ctxt->valueMax *= 2;
2873 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002874 }
2875 ctxt->valueTab[ctxt->valueNr] = value;
2876 ctxt->value = value;
2877 return (ctxt->valueNr++);
2878}
Owen Taylor3473f882001-02-23 17:55:21 +00002879
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002880/**
2881 * xmlXPathPopBoolean:
2882 * @ctxt: an XPath parser context
2883 *
2884 * Pops a boolean from the stack, handling conversion if needed.
2885 * Check error with #xmlXPathCheckError.
2886 *
2887 * Returns the boolean
2888 */
2889int
2890xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2891 xmlXPathObjectPtr obj;
2892 int ret;
2893
2894 obj = valuePop(ctxt);
2895 if (obj == NULL) {
2896 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2897 return(0);
2898 }
William M. Brack08171912003-12-29 02:52:11 +00002899 if (obj->type != XPATH_BOOLEAN)
2900 ret = xmlXPathCastToBoolean(obj);
2901 else
2902 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002903 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002904 return(ret);
2905}
2906
2907/**
2908 * xmlXPathPopNumber:
2909 * @ctxt: an XPath parser context
2910 *
2911 * Pops a number from the stack, handling conversion if needed.
2912 * Check error with #xmlXPathCheckError.
2913 *
2914 * Returns the number
2915 */
2916double
2917xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2918 xmlXPathObjectPtr obj;
2919 double ret;
2920
2921 obj = valuePop(ctxt);
2922 if (obj == NULL) {
2923 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2924 return(0);
2925 }
William M. Brack08171912003-12-29 02:52:11 +00002926 if (obj->type != XPATH_NUMBER)
2927 ret = xmlXPathCastToNumber(obj);
2928 else
2929 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002930 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002931 return(ret);
2932}
2933
2934/**
2935 * xmlXPathPopString:
2936 * @ctxt: an XPath parser context
2937 *
2938 * Pops a string from the stack, handling conversion if needed.
2939 * Check error with #xmlXPathCheckError.
2940 *
2941 * Returns the string
2942 */
2943xmlChar *
2944xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2945 xmlXPathObjectPtr obj;
2946 xmlChar * ret;
2947
2948 obj = valuePop(ctxt);
2949 if (obj == NULL) {
2950 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2951 return(NULL);
2952 }
William M. Brack08171912003-12-29 02:52:11 +00002953 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002954 /* TODO: needs refactoring somewhere else */
2955 if (obj->stringval == ret)
2956 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002957 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002958 return(ret);
2959}
2960
2961/**
2962 * xmlXPathPopNodeSet:
2963 * @ctxt: an XPath parser context
2964 *
2965 * Pops a node-set from the stack, handling conversion if needed.
2966 * Check error with #xmlXPathCheckError.
2967 *
2968 * Returns the node-set
2969 */
2970xmlNodeSetPtr
2971xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2972 xmlXPathObjectPtr obj;
2973 xmlNodeSetPtr ret;
2974
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002975 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002976 if (ctxt->value == NULL) {
2977 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2978 return(NULL);
2979 }
2980 if (!xmlXPathStackIsNodeSet(ctxt)) {
2981 xmlXPathSetTypeError(ctxt);
2982 return(NULL);
2983 }
2984 obj = valuePop(ctxt);
2985 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002986#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002987 /* to fix memory leak of not clearing obj->user */
2988 if (obj->boolval && obj->user != NULL)
2989 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002990#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002991 obj->nodesetval = NULL;
2992 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002993 return(ret);
2994}
2995
2996/**
2997 * xmlXPathPopExternal:
2998 * @ctxt: an XPath parser context
2999 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003000 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003001 * Check error with #xmlXPathCheckError.
3002 *
3003 * Returns the object
3004 */
3005void *
3006xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3007 xmlXPathObjectPtr obj;
3008 void * ret;
3009
Daniel Veillarda82b1822004-11-08 16:24:57 +00003010 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003011 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3012 return(NULL);
3013 }
3014 if (ctxt->value->type != XPATH_USERS) {
3015 xmlXPathSetTypeError(ctxt);
3016 return(NULL);
3017 }
3018 obj = valuePop(ctxt);
3019 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003020 obj->user = NULL;
3021 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003022 return(ret);
3023}
3024
Owen Taylor3473f882001-02-23 17:55:21 +00003025/*
3026 * Macros for accessing the content. Those should be used only by the parser,
3027 * and not exported.
3028 *
3029 * Dirty macros, i.e. one need to make assumption on the context to use them
3030 *
3031 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3032 * CUR returns the current xmlChar value, i.e. a 8 bit value
3033 * in ISO-Latin or UTF-8.
3034 * This should be used internally by the parser
3035 * only to compare to ASCII values otherwise it would break when
3036 * running with UTF-8 encoding.
3037 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3038 * to compare on ASCII based substring.
3039 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3040 * strings within the parser.
3041 * CURRENT Returns the current char value, with the full decoding of
3042 * UTF-8 if we are using this mode. It returns an int.
3043 * NEXT Skip to the next character, this does the proper decoding
3044 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3045 * It returns the pointer to the current xmlChar.
3046 */
3047
3048#define CUR (*ctxt->cur)
3049#define SKIP(val) ctxt->cur += (val)
3050#define NXT(val) ctxt->cur[(val)]
3051#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00003052#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3053
3054#define COPY_BUF(l,b,i,v) \
3055 if (l == 1) b[i++] = (xmlChar) v; \
3056 else i += xmlCopyChar(l,&b[i],v)
3057
3058#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00003059
Daniel Veillard45490ae2008-07-29 09:13:19 +00003060#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00003061 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00003062
3063#define CURRENT (*ctxt->cur)
3064#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3065
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003066
3067#ifndef DBL_DIG
3068#define DBL_DIG 16
3069#endif
3070#ifndef DBL_EPSILON
3071#define DBL_EPSILON 1E-9
3072#endif
3073
3074#define UPPER_DOUBLE 1E9
3075#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00003076#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003077
3078#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00003079#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003080#define EXPONENT_DIGITS (3 + 2)
3081
3082/**
3083 * xmlXPathFormatNumber:
3084 * @number: number to format
3085 * @buffer: output buffer
3086 * @buffersize: size of output buffer
3087 *
3088 * Convert the number into a string representation.
3089 */
3090static void
3091xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3092{
Daniel Veillardcda96922001-08-21 10:56:31 +00003093 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003094 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003095 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003096 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003097 break;
3098 case -1:
3099 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003100 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003101 break;
3102 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003103 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003104 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003105 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003106 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00003107 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003108 } else if (number == ((int) number)) {
3109 char work[30];
3110 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00003111 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003112
3113 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003114 if (value == 0) {
3115 *ptr++ = '0';
3116 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00003117 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003118 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00003119 while ((*cur) && (ptr - buffer < buffersize)) {
3120 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00003121 }
3122 }
3123 if (ptr - buffer < buffersize) {
3124 *ptr = 0;
3125 } else if (buffersize > 0) {
3126 ptr--;
3127 *ptr = 0;
3128 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003129 } else {
William M. Brackca797882007-05-11 14:45:53 +00003130 /*
3131 For the dimension of work,
3132 DBL_DIG is number of significant digits
3133 EXPONENT is only needed for "scientific notation"
3134 3 is sign, decimal point, and terminating zero
3135 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3136 Note that this dimension is slightly (a few characters)
3137 larger than actually necessary.
3138 */
3139 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003140 int integer_place, fraction_place;
3141 char *ptr;
3142 char *after_fraction;
3143 double absolute_value;
3144 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003145
Bjorn Reese70a9da52001-04-21 16:57:29 +00003146 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003147
Bjorn Reese70a9da52001-04-21 16:57:29 +00003148 /*
3149 * First choose format - scientific or regular floating point.
3150 * In either case, result is in work, and after_fraction points
3151 * just past the fractional part.
3152 */
3153 if ( ((absolute_value > UPPER_DOUBLE) ||
3154 (absolute_value < LOWER_DOUBLE)) &&
3155 (absolute_value != 0.0) ) {
3156 /* Use scientific notation */
3157 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3158 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003159 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00003160 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00003161 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00003162
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003163 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003164 else {
3165 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00003166 if (absolute_value > 0.0) {
3167 integer_place = (int)log10(absolute_value);
3168 if (integer_place > 0)
3169 fraction_place = DBL_DIG - integer_place - 1;
3170 else
3171 fraction_place = DBL_DIG - integer_place;
3172 } else {
3173 fraction_place = 1;
3174 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003175 size = snprintf(work, sizeof(work), "%0.*f",
3176 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003177 }
3178
Daniel Veillardb9e4d5b2013-07-22 13:21:31 +08003179 /* Remove leading spaces sometimes inserted by snprintf */
3180 while (work[0] == ' ') {
3181 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3182 size--;
3183 }
3184
Bjorn Reese70a9da52001-04-21 16:57:29 +00003185 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00003186 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003187 ptr = after_fraction;
3188 while (*(--ptr) == '0')
3189 ;
3190 if (*ptr != '.')
3191 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003192 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003193
3194 /* Finally copy result back to caller */
3195 size = strlen(work) + 1;
3196 if (size > buffersize) {
3197 work[buffersize - 1] = 0;
3198 size = buffersize;
3199 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00003200 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003201 }
3202 break;
3203 }
3204}
3205
Owen Taylor3473f882001-02-23 17:55:21 +00003206
3207/************************************************************************
3208 * *
3209 * Routines to handle NodeSets *
3210 * *
3211 ************************************************************************/
3212
3213/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003214 * xmlXPathOrderDocElems:
3215 * @doc: an input document
3216 *
3217 * Call this routine to speed up XPath computation on static documents.
3218 * This stamps all the element nodes with the document order
3219 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00003220 * field, the value stored is actually - the node number (starting at -1)
3221 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003222 *
William M. Brack08171912003-12-29 02:52:11 +00003223 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003224 * of error.
3225 */
3226long
3227xmlXPathOrderDocElems(xmlDocPtr doc) {
3228 long count = 0;
3229 xmlNodePtr cur;
3230
3231 if (doc == NULL)
3232 return(-1);
3233 cur = doc->children;
3234 while (cur != NULL) {
3235 if (cur->type == XML_ELEMENT_NODE) {
3236 cur->content = (void *) (-(++count));
3237 if (cur->children != NULL) {
3238 cur = cur->children;
3239 continue;
3240 }
3241 }
3242 if (cur->next != NULL) {
3243 cur = cur->next;
3244 continue;
3245 }
3246 do {
3247 cur = cur->parent;
3248 if (cur == NULL)
3249 break;
3250 if (cur == (xmlNodePtr) doc) {
3251 cur = NULL;
3252 break;
3253 }
3254 if (cur->next != NULL) {
3255 cur = cur->next;
3256 break;
3257 }
3258 } while (cur != NULL);
3259 }
3260 return(count);
3261}
3262
3263/**
Owen Taylor3473f882001-02-23 17:55:21 +00003264 * xmlXPathCmpNodes:
3265 * @node1: the first node
3266 * @node2: the second node
3267 *
3268 * Compare two nodes w.r.t document order
3269 *
3270 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00003271 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003272 */
3273int
3274xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3275 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003276 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003277 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003278 xmlNodePtr cur, root;
3279
3280 if ((node1 == NULL) || (node2 == NULL))
3281 return(-2);
3282 /*
3283 * a couple of optimizations which will avoid computations in most cases
3284 */
William M. Brackee0b9822007-03-07 08:15:01 +00003285 if (node1 == node2) /* trivial case */
3286 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00003287 if (node1->type == XML_ATTRIBUTE_NODE) {
3288 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003289 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003290 node1 = node1->parent;
3291 }
3292 if (node2->type == XML_ATTRIBUTE_NODE) {
3293 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00003294 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00003295 node2 = node2->parent;
3296 }
3297 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00003298 if (attr1 == attr2) {
3299 /* not required, but we keep attributes in order */
3300 if (attr1 != 0) {
3301 cur = attrNode2->prev;
3302 while (cur != NULL) {
3303 if (cur == attrNode1)
3304 return (1);
3305 cur = cur->prev;
3306 }
3307 return (-1);
3308 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003309 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00003310 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003311 if (attr2 == 1)
3312 return(1);
3313 return(-1);
3314 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003315 if ((node1->type == XML_NAMESPACE_DECL) ||
3316 (node2->type == XML_NAMESPACE_DECL))
3317 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003318 if (node1 == node2->prev)
3319 return(1);
3320 if (node1 == node2->next)
3321 return(-1);
3322
3323 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003324 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003325 */
3326 if ((node1->type == XML_ELEMENT_NODE) &&
3327 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003328 (0 > (long) node1->content) &&
3329 (0 > (long) node2->content) &&
3330 (node1->doc == node2->doc)) {
3331 long l1, l2;
3332
3333 l1 = -((long) node1->content);
3334 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003335 if (l1 < l2)
3336 return(1);
3337 if (l1 > l2)
3338 return(-1);
3339 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003340
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003341 /*
Owen Taylor3473f882001-02-23 17:55:21 +00003342 * compute depth to root
3343 */
3344 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3345 if (cur == node1)
3346 return(1);
3347 depth2++;
3348 }
3349 root = cur;
3350 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3351 if (cur == node2)
3352 return(-1);
3353 depth1++;
3354 }
3355 /*
3356 * Distinct document (or distinct entities :-( ) case.
3357 */
3358 if (root != cur) {
3359 return(-2);
3360 }
3361 /*
3362 * get the nearest common ancestor.
3363 */
3364 while (depth1 > depth2) {
3365 depth1--;
3366 node1 = node1->parent;
3367 }
3368 while (depth2 > depth1) {
3369 depth2--;
3370 node2 = node2->parent;
3371 }
3372 while (node1->parent != node2->parent) {
3373 node1 = node1->parent;
3374 node2 = node2->parent;
3375 /* should not happen but just in case ... */
3376 if ((node1 == NULL) || (node2 == NULL))
3377 return(-2);
3378 }
3379 /*
3380 * Find who's first.
3381 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003382 if (node1 == node2->prev)
3383 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003384 if (node1 == node2->next)
3385 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003386 /*
3387 * Speedup using document order if availble.
3388 */
3389 if ((node1->type == XML_ELEMENT_NODE) &&
3390 (node2->type == XML_ELEMENT_NODE) &&
3391 (0 > (long) node1->content) &&
3392 (0 > (long) node2->content) &&
3393 (node1->doc == node2->doc)) {
3394 long l1, l2;
3395
3396 l1 = -((long) node1->content);
3397 l2 = -((long) node2->content);
3398 if (l1 < l2)
3399 return(1);
3400 if (l1 > l2)
3401 return(-1);
3402 }
3403
Owen Taylor3473f882001-02-23 17:55:21 +00003404 for (cur = node1->next;cur != NULL;cur = cur->next)
3405 if (cur == node2)
3406 return(1);
3407 return(-1); /* assume there is no sibling list corruption */
3408}
3409
3410/**
3411 * xmlXPathNodeSetSort:
3412 * @set: the node set
3413 *
3414 * Sort the node set in document order
3415 */
3416void
3417xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Vojtech Fried3e031b72012-08-24 16:52:44 +08003418#ifndef WITH_TIM_SORT
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003419 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003420 xmlNodePtr tmp;
Vojtech Fried3e031b72012-08-24 16:52:44 +08003421#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003422
3423 if (set == NULL)
3424 return;
3425
Vojtech Fried3e031b72012-08-24 16:52:44 +08003426#ifndef WITH_TIM_SORT
3427 /*
3428 * Use the old Shell's sort implementation to sort the node-set
3429 * Timsort ought to be quite faster
3430 */
Owen Taylor3473f882001-02-23 17:55:21 +00003431 len = set->nodeNr;
3432 for (incr = len / 2; incr > 0; incr /= 2) {
3433 for (i = incr; i < len; i++) {
3434 j = i - incr;
3435 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003436#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003437 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3438 set->nodeTab[j + incr]) == -1)
3439#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003440 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003441 set->nodeTab[j + incr]) == -1)
3442#endif
3443 {
Owen Taylor3473f882001-02-23 17:55:21 +00003444 tmp = set->nodeTab[j];
3445 set->nodeTab[j] = set->nodeTab[j + incr];
3446 set->nodeTab[j + incr] = tmp;
3447 j -= incr;
3448 } else
3449 break;
3450 }
3451 }
3452 }
Vojtech Fried3e031b72012-08-24 16:52:44 +08003453#else /* WITH_TIM_SORT */
3454 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3455#endif /* WITH_TIM_SORT */
Owen Taylor3473f882001-02-23 17:55:21 +00003456}
3457
3458#define XML_NODESET_DEFAULT 10
3459/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003460 * xmlXPathNodeSetDupNs:
3461 * @node: the parent node of the namespace XPath node
3462 * @ns: the libxml namespace declaration node.
3463 *
3464 * Namespace node in libxml don't match the XPath semantic. In a node set
3465 * the namespace nodes are duplicated and the next pointer is set to the
3466 * parent node in the XPath semantic.
3467 *
3468 * Returns the newly created object.
3469 */
3470static xmlNodePtr
3471xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3472 xmlNsPtr cur;
3473
3474 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3475 return(NULL);
3476 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3477 return((xmlNodePtr) ns);
3478
3479 /*
3480 * Allocate a new Namespace and fill the fields.
3481 */
3482 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3483 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003484 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003485 return(NULL);
3486 }
3487 memset(cur, 0, sizeof(xmlNs));
3488 cur->type = XML_NAMESPACE_DECL;
3489 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003490 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003491 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003492 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003493 cur->next = (xmlNsPtr) node;
3494 return((xmlNodePtr) cur);
3495}
3496
3497/**
3498 * xmlXPathNodeSetFreeNs:
3499 * @ns: the XPath namespace node found in a nodeset.
3500 *
William M. Brack08171912003-12-29 02:52:11 +00003501 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003502 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003503 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003504 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003505void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003506xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3507 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3508 return;
3509
3510 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3511 if (ns->href != NULL)
3512 xmlFree((xmlChar *)ns->href);
3513 if (ns->prefix != NULL)
3514 xmlFree((xmlChar *)ns->prefix);
3515 xmlFree(ns);
3516 }
3517}
3518
3519/**
Owen Taylor3473f882001-02-23 17:55:21 +00003520 * xmlXPathNodeSetCreate:
3521 * @val: an initial xmlNodePtr, or NULL
3522 *
3523 * Create a new xmlNodeSetPtr of type double and of value @val
3524 *
3525 * Returns the newly created object.
3526 */
3527xmlNodeSetPtr
3528xmlXPathNodeSetCreate(xmlNodePtr val) {
3529 xmlNodeSetPtr ret;
3530
3531 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3532 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003533 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003534 return(NULL);
3535 }
3536 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3537 if (val != NULL) {
3538 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3539 sizeof(xmlNodePtr));
3540 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003541 xmlXPathErrMemory(NULL, "creating nodeset\n");
3542 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003543 return(NULL);
3544 }
3545 memset(ret->nodeTab, 0 ,
3546 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3547 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003548 if (val->type == XML_NAMESPACE_DECL) {
3549 xmlNsPtr ns = (xmlNsPtr) val;
3550
3551 ret->nodeTab[ret->nodeNr++] =
3552 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3553 } else
3554 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003555 }
3556 return(ret);
3557}
3558
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003559/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003560 * xmlXPathNodeSetCreateSize:
3561 * @size: the initial size of the set
3562 *
3563 * Create a new xmlNodeSetPtr of type double and of value @val
3564 *
3565 * Returns the newly created object.
3566 */
3567static xmlNodeSetPtr
3568xmlXPathNodeSetCreateSize(int size) {
3569 xmlNodeSetPtr ret;
3570
3571 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3572 if (ret == NULL) {
3573 xmlXPathErrMemory(NULL, "creating nodeset\n");
3574 return(NULL);
3575 }
3576 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3577 if (size < XML_NODESET_DEFAULT)
3578 size = XML_NODESET_DEFAULT;
3579 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3580 if (ret->nodeTab == NULL) {
3581 xmlXPathErrMemory(NULL, "creating nodeset\n");
3582 xmlFree(ret);
3583 return(NULL);
3584 }
3585 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003586 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003587 return(ret);
3588}
3589
3590/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003591 * xmlXPathNodeSetContains:
3592 * @cur: the node-set
3593 * @val: the node
3594 *
3595 * checks whether @cur contains @val
3596 *
3597 * Returns true (1) if @cur contains @val, false (0) otherwise
3598 */
3599int
3600xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3601 int i;
3602
Daniel Veillarda82b1822004-11-08 16:24:57 +00003603 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003604 if (val->type == XML_NAMESPACE_DECL) {
3605 for (i = 0; i < cur->nodeNr; i++) {
3606 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3607 xmlNsPtr ns1, ns2;
3608
3609 ns1 = (xmlNsPtr) val;
3610 ns2 = (xmlNsPtr) cur->nodeTab[i];
3611 if (ns1 == ns2)
3612 return(1);
3613 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3614 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3615 return(1);
3616 }
3617 }
3618 } else {
3619 for (i = 0; i < cur->nodeNr; i++) {
3620 if (cur->nodeTab[i] == val)
3621 return(1);
3622 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003623 }
3624 return(0);
3625}
3626
3627/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003628 * xmlXPathNodeSetAddNs:
3629 * @cur: the initial node set
3630 * @node: the hosting node
3631 * @ns: a the namespace node
3632 *
3633 * add a new namespace node to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003634 *
3635 * Returns 0 in case of success and -1 in case of error
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003636 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003637int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003638xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3639 int i;
3640
Daniel Veillard45490ae2008-07-29 09:13:19 +00003641
Daniel Veillarda82b1822004-11-08 16:24:57 +00003642 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3643 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003644 (node->type != XML_ELEMENT_NODE))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003645 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003646
William M. Brack08171912003-12-29 02:52:11 +00003647 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003648 /*
William M. Brack08171912003-12-29 02:52:11 +00003649 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003650 */
3651 for (i = 0;i < cur->nodeNr;i++) {
3652 if ((cur->nodeTab[i] != NULL) &&
3653 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003654 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003655 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003656 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003657 }
3658
3659 /*
3660 * grow the nodeTab if needed
3661 */
3662 if (cur->nodeMax == 0) {
3663 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3664 sizeof(xmlNodePtr));
3665 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003666 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003667 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003668 }
3669 memset(cur->nodeTab, 0 ,
3670 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3671 cur->nodeMax = XML_NODESET_DEFAULT;
3672 } else if (cur->nodeNr == cur->nodeMax) {
3673 xmlNodePtr *temp;
3674
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003675 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3676 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003677 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003678 }
Chris Evansd7958b22011-03-23 08:13:06 +08003679 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003680 sizeof(xmlNodePtr));
3681 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003682 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003683 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003684 }
Chris Evansd7958b22011-03-23 08:13:06 +08003685 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003686 cur->nodeTab = temp;
3687 }
3688 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003689 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003690}
3691
3692/**
Owen Taylor3473f882001-02-23 17:55:21 +00003693 * xmlXPathNodeSetAdd:
3694 * @cur: the initial node set
3695 * @val: a new xmlNodePtr
3696 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003697 * add a new xmlNodePtr to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003698 *
3699 * Returns 0 in case of success, and -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00003700 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003701int
Owen Taylor3473f882001-02-23 17:55:21 +00003702xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3703 int i;
3704
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003705 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003706
William M. Brack08171912003-12-29 02:52:11 +00003707 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003708 /*
Xin Li28c53d32017-03-07 00:33:02 +00003709 * prevent duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003710 */
3711 for (i = 0;i < cur->nodeNr;i++)
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003712 if (cur->nodeTab[i] == val) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003713
3714 /*
3715 * grow the nodeTab if needed
3716 */
3717 if (cur->nodeMax == 0) {
3718 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3719 sizeof(xmlNodePtr));
3720 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003721 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003722 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003723 }
3724 memset(cur->nodeTab, 0 ,
3725 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3726 cur->nodeMax = XML_NODESET_DEFAULT;
3727 } else if (cur->nodeNr == cur->nodeMax) {
3728 xmlNodePtr *temp;
3729
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003730 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3731 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003732 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003733 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003734 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003735 sizeof(xmlNodePtr));
3736 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003737 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003738 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003739 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003740 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003741 cur->nodeTab = temp;
3742 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003743 if (val->type == XML_NAMESPACE_DECL) {
3744 xmlNsPtr ns = (xmlNsPtr) val;
3745
Daniel Veillard45490ae2008-07-29 09:13:19 +00003746 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003747 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3748 } else
3749 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003750 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003751}
3752
3753/**
3754 * xmlXPathNodeSetAddUnique:
3755 * @cur: the initial node set
3756 * @val: a new xmlNodePtr
3757 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003758 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003759 * when we are sure the node is not already in the set.
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003760 *
3761 * Returns 0 in case of success and -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00003762 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003763int
Owen Taylor3473f882001-02-23 17:55:21 +00003764xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003765 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003766
William M. Brack08171912003-12-29 02:52:11 +00003767 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003768 /*
3769 * grow the nodeTab if needed
3770 */
3771 if (cur->nodeMax == 0) {
3772 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3773 sizeof(xmlNodePtr));
3774 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003775 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003776 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003777 }
3778 memset(cur->nodeTab, 0 ,
3779 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3780 cur->nodeMax = XML_NODESET_DEFAULT;
3781 } else if (cur->nodeNr == cur->nodeMax) {
3782 xmlNodePtr *temp;
3783
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003784 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3785 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003786 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003787 }
Chris Evansd7958b22011-03-23 08:13:06 +08003788 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003789 sizeof(xmlNodePtr));
3790 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003791 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003792 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003793 }
3794 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003795 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003796 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003797 if (val->type == XML_NAMESPACE_DECL) {
3798 xmlNsPtr ns = (xmlNsPtr) val;
3799
Daniel Veillard45490ae2008-07-29 09:13:19 +00003800 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003801 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3802 } else
3803 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003804 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003805}
3806
3807/**
3808 * xmlXPathNodeSetMerge:
3809 * @val1: the first NodeSet or NULL
3810 * @val2: the second NodeSet
3811 *
3812 * Merges two nodesets, all nodes from @val2 are added to @val1
3813 * if @val1 is NULL, a new set is created and copied from @val2
3814 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003815 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003816 */
3817xmlNodeSetPtr
3818xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003819 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003820 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003821
3822 if (val2 == NULL) return(val1);
3823 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003824 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003825 if (val1 == NULL)
3826 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003827#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003828 /*
3829 * TODO: The optimization won't work in every case, since
3830 * those nasty namespace nodes need to be added with
3831 * xmlXPathNodeSetDupNs() to the set; thus a pure
3832 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003833 * If there was a flag on the nodesetval, indicating that
3834 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003835 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003836 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003837 * Optimization: Create an equally sized node-set
3838 * and memcpy the content.
3839 */
3840 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3841 if (val1 == NULL)
3842 return(NULL);
3843 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003844 if (val2->nodeNr == 1)
3845 *(val1->nodeTab) = *(val2->nodeTab);
3846 else {
3847 memcpy(val1->nodeTab, val2->nodeTab,
3848 val2->nodeNr * sizeof(xmlNodePtr));
3849 }
3850 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003851 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003852 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003853#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003854 }
3855
William M. Brack08171912003-12-29 02:52:11 +00003856 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003857 initNr = val1->nodeNr;
3858
3859 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003860 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003861 /*
William M. Brack08171912003-12-29 02:52:11 +00003862 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003863 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003864 skip = 0;
3865 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003866 n1 = val1->nodeTab[j];
3867 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003868 skip = 1;
3869 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003870 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003871 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003872 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3873 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3874 ((xmlNsPtr) n2)->prefix)))
3875 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003876 skip = 1;
3877 break;
3878 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003879 }
3880 }
3881 if (skip)
3882 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003883
3884 /*
3885 * grow the nodeTab if needed
3886 */
3887 if (val1->nodeMax == 0) {
3888 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3889 sizeof(xmlNodePtr));
3890 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003891 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003892 return(NULL);
3893 }
3894 memset(val1->nodeTab, 0 ,
3895 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3896 val1->nodeMax = XML_NODESET_DEFAULT;
3897 } else if (val1->nodeNr == val1->nodeMax) {
3898 xmlNodePtr *temp;
3899
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003900 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3901 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3902 return(NULL);
3903 }
Chris Evansd7958b22011-03-23 08:13:06 +08003904 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003905 sizeof(xmlNodePtr));
3906 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003907 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003908 return(NULL);
3909 }
3910 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003911 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003912 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003913 if (n2->type == XML_NAMESPACE_DECL) {
3914 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003915
3916 val1->nodeTab[val1->nodeNr++] =
3917 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3918 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003919 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003920 }
3921
3922 return(val1);
3923}
3924
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003925
3926/**
3927 * xmlXPathNodeSetMergeAndClear:
3928 * @set1: the first NodeSet or NULL
3929 * @set2: the second NodeSet
3930 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3931 *
3932 * Merges two nodesets, all nodes from @set2 are added to @set1
3933 * if @set1 is NULL, a new set is created and copied from @set2.
3934 * Checks for duplicate nodes. Clears set2.
3935 *
3936 * Returns @set1 once extended or NULL in case of error.
3937 */
3938static xmlNodeSetPtr
3939xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3940 int hasNullEntries)
3941{
3942 if ((set1 == NULL) && (hasNullEntries == 0)) {
3943 /*
3944 * Note that doing a memcpy of the list, namespace nodes are
3945 * just assigned to set1, since set2 is cleared anyway.
3946 */
3947 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3948 if (set1 == NULL)
3949 return(NULL);
3950 if (set2->nodeNr != 0) {
3951 memcpy(set1->nodeTab, set2->nodeTab,
3952 set2->nodeNr * sizeof(xmlNodePtr));
3953 set1->nodeNr = set2->nodeNr;
3954 }
3955 } else {
3956 int i, j, initNbSet1;
3957 xmlNodePtr n1, n2;
3958
3959 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003960 set1 = xmlXPathNodeSetCreate(NULL);
3961 if (set1 == NULL)
3962 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003963
Daniel Veillard45490ae2008-07-29 09:13:19 +00003964 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003965 for (i = 0;i < set2->nodeNr;i++) {
3966 n2 = set2->nodeTab[i];
3967 /*
3968 * Skip NULLed entries.
3969 */
3970 if (n2 == NULL)
3971 continue;
3972 /*
3973 * Skip duplicates.
3974 */
3975 for (j = 0; j < initNbSet1; j++) {
3976 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003977 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003978 goto skip_node;
3979 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3980 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003981 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003982 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3983 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3984 ((xmlNsPtr) n2)->prefix)))
3985 {
3986 /*
3987 * Free the namespace node.
3988 */
3989 set2->nodeTab[i] = NULL;
3990 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3991 goto skip_node;
3992 }
3993 }
3994 }
3995 /*
3996 * grow the nodeTab if needed
3997 */
3998 if (set1->nodeMax == 0) {
3999 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4000 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4001 if (set1->nodeTab == NULL) {
4002 xmlXPathErrMemory(NULL, "merging nodeset\n");
4003 return(NULL);
4004 }
4005 memset(set1->nodeTab, 0,
4006 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4007 set1->nodeMax = XML_NODESET_DEFAULT;
4008 } else if (set1->nodeNr >= set1->nodeMax) {
4009 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004010
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004011 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4012 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4013 return(NULL);
4014 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004015 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004016 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004017 if (temp == NULL) {
4018 xmlXPathErrMemory(NULL, "merging nodeset\n");
4019 return(NULL);
4020 }
4021 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004022 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004023 }
4024 if (n2->type == XML_NAMESPACE_DECL) {
4025 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004026
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004027 set1->nodeTab[set1->nodeNr++] =
4028 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
4029 } else
4030 set1->nodeTab[set1->nodeNr++] = n2;
4031skip_node:
4032 {}
4033 }
4034 }
4035 set2->nodeNr = 0;
4036 return(set1);
4037}
4038
4039/**
4040 * xmlXPathNodeSetMergeAndClearNoDupls:
4041 * @set1: the first NodeSet or NULL
4042 * @set2: the second NodeSet
4043 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4044 *
4045 * Merges two nodesets, all nodes from @set2 are added to @set1
4046 * if @set1 is NULL, a new set is created and copied from @set2.
4047 * Doesn't chack for duplicate nodes. Clears set2.
4048 *
4049 * Returns @set1 once extended or NULL in case of error.
4050 */
4051static xmlNodeSetPtr
4052xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4053 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004054{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004055 if (set2 == NULL)
4056 return(set1);
4057 if ((set1 == NULL) && (hasNullEntries == 0)) {
4058 /*
4059 * Note that doing a memcpy of the list, namespace nodes are
4060 * just assigned to set1, since set2 is cleared anyway.
4061 */
4062 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4063 if (set1 == NULL)
4064 return(NULL);
4065 if (set2->nodeNr != 0) {
4066 memcpy(set1->nodeTab, set2->nodeTab,
4067 set2->nodeNr * sizeof(xmlNodePtr));
4068 set1->nodeNr = set2->nodeNr;
4069 }
4070 } else {
4071 int i;
4072 xmlNodePtr n2;
4073
4074 if (set1 == NULL)
4075 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004076 if (set1 == NULL)
4077 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004078
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004079 for (i = 0;i < set2->nodeNr;i++) {
4080 n2 = set2->nodeTab[i];
4081 /*
4082 * Skip NULLed entries.
4083 */
4084 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004085 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004086 if (set1->nodeMax == 0) {
4087 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4088 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4089 if (set1->nodeTab == NULL) {
4090 xmlXPathErrMemory(NULL, "merging nodeset\n");
4091 return(NULL);
4092 }
4093 memset(set1->nodeTab, 0,
4094 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4095 set1->nodeMax = XML_NODESET_DEFAULT;
4096 } else if (set1->nodeNr >= set1->nodeMax) {
4097 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004098
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004099 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4100 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4101 return(NULL);
4102 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004103 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004104 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004105 if (temp == NULL) {
4106 xmlXPathErrMemory(NULL, "merging nodeset\n");
4107 return(NULL);
4108 }
4109 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004110 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004111 }
4112 set1->nodeTab[set1->nodeNr++] = n2;
4113 }
4114 }
4115 set2->nodeNr = 0;
4116 return(set1);
4117}
Daniel Veillard75be0132002-03-13 10:03:35 +00004118
4119/**
Owen Taylor3473f882001-02-23 17:55:21 +00004120 * xmlXPathNodeSetDel:
4121 * @cur: the initial node set
4122 * @val: an xmlNodePtr
4123 *
4124 * Removes an xmlNodePtr from an existing NodeSet
4125 */
4126void
4127xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4128 int i;
4129
4130 if (cur == NULL) return;
4131 if (val == NULL) return;
4132
4133 /*
William M. Brack08171912003-12-29 02:52:11 +00004134 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004135 */
4136 for (i = 0;i < cur->nodeNr;i++)
4137 if (cur->nodeTab[i] == val) break;
4138
William M. Brack08171912003-12-29 02:52:11 +00004139 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004140#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004141 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004142 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4143 val->name);
4144#endif
4145 return;
4146 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004147 if ((cur->nodeTab[i] != NULL) &&
4148 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4149 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004150 cur->nodeNr--;
4151 for (;i < cur->nodeNr;i++)
4152 cur->nodeTab[i] = cur->nodeTab[i + 1];
4153 cur->nodeTab[cur->nodeNr] = NULL;
4154}
4155
4156/**
4157 * xmlXPathNodeSetRemove:
4158 * @cur: the initial node set
4159 * @val: the index to remove
4160 *
4161 * Removes an entry from an existing NodeSet list.
4162 */
4163void
4164xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4165 if (cur == NULL) return;
4166 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004167 if ((cur->nodeTab[val] != NULL) &&
4168 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4169 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004170 cur->nodeNr--;
4171 for (;val < cur->nodeNr;val++)
4172 cur->nodeTab[val] = cur->nodeTab[val + 1];
4173 cur->nodeTab[cur->nodeNr] = NULL;
4174}
4175
4176/**
4177 * xmlXPathFreeNodeSet:
4178 * @obj: the xmlNodeSetPtr to free
4179 *
4180 * Free the NodeSet compound (not the actual nodes !).
4181 */
4182void
4183xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4184 if (obj == NULL) return;
4185 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004186 int i;
4187
William M. Brack08171912003-12-29 02:52:11 +00004188 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004189 for (i = 0;i < obj->nodeNr;i++)
4190 if ((obj->nodeTab[i] != NULL) &&
4191 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4192 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004193 xmlFree(obj->nodeTab);
4194 }
Owen Taylor3473f882001-02-23 17:55:21 +00004195 xmlFree(obj);
4196}
4197
4198/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004199 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004200 * @set: the node set to clear
Daniel Veillard45490ae2008-07-29 09:13:19 +00004201 *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004202 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4203 * are feed), but does *not* free the list itself. Sets the length of the
4204 * list to 0.
4205 */
4206static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004207xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4208{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004209 if ((set == NULL) || (set->nodeNr <= 0))
4210 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004211 else if (hasNsNodes) {
4212 int i;
4213 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004214
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004215 for (i = 0; i < set->nodeNr; i++) {
4216 node = set->nodeTab[i];
4217 if ((node != NULL) &&
4218 (node->type == XML_NAMESPACE_DECL))
4219 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004220 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004221 }
4222 set->nodeNr = 0;
4223}
4224
4225/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004226 * xmlXPathNodeSetClearFromPos:
4227 * @set: the node set to be cleared
4228 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004229 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004230 * Clears the list from temporary XPath objects (e.g. namespace nodes
4231 * are feed) starting with the entry at @pos, but does *not* free the list
4232 * itself. Sets the length of the list to @pos.
4233 */
4234static void
4235xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4236{
4237 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4238 return;
4239 else if ((hasNsNodes)) {
4240 int i;
4241 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004242
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004243 for (i = pos; i < set->nodeNr; i++) {
4244 node = set->nodeTab[i];
4245 if ((node != NULL) &&
4246 (node->type == XML_NAMESPACE_DECL))
4247 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004248 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004249 }
4250 set->nodeNr = pos;
4251}
4252
4253/**
Owen Taylor3473f882001-02-23 17:55:21 +00004254 * xmlXPathFreeValueTree:
4255 * @obj: the xmlNodeSetPtr to free
4256 *
4257 * Free the NodeSet compound and the actual tree, this is different
4258 * from xmlXPathFreeNodeSet()
4259 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004260static void
Owen Taylor3473f882001-02-23 17:55:21 +00004261xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4262 int i;
4263
4264 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004265
4266 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004267 for (i = 0;i < obj->nodeNr;i++) {
4268 if (obj->nodeTab[i] != NULL) {
4269 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4270 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4271 } else {
4272 xmlFreeNodeList(obj->nodeTab[i]);
4273 }
4274 }
4275 }
Owen Taylor3473f882001-02-23 17:55:21 +00004276 xmlFree(obj->nodeTab);
4277 }
Owen Taylor3473f882001-02-23 17:55:21 +00004278 xmlFree(obj);
4279}
4280
4281#if defined(DEBUG) || defined(DEBUG_STEP)
4282/**
4283 * xmlGenericErrorContextNodeSet:
4284 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004285 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004286 *
4287 * Quick display of a NodeSet
4288 */
4289void
4290xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4291 int i;
4292
4293 if (output == NULL) output = xmlGenericErrorContext;
4294 if (obj == NULL) {
4295 fprintf(output, "NodeSet == NULL !\n");
4296 return;
4297 }
4298 if (obj->nodeNr == 0) {
4299 fprintf(output, "NodeSet is empty\n");
4300 return;
4301 }
4302 if (obj->nodeTab == NULL) {
4303 fprintf(output, " nodeTab == NULL !\n");
4304 return;
4305 }
4306 for (i = 0; i < obj->nodeNr; i++) {
4307 if (obj->nodeTab[i] == NULL) {
4308 fprintf(output, " NULL !\n");
4309 return;
4310 }
4311 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4312 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4313 fprintf(output, " /");
4314 else if (obj->nodeTab[i]->name == NULL)
4315 fprintf(output, " noname!");
4316 else fprintf(output, " %s", obj->nodeTab[i]->name);
4317 }
4318 fprintf(output, "\n");
4319}
4320#endif
4321
4322/**
4323 * xmlXPathNewNodeSet:
4324 * @val: the NodePtr value
4325 *
4326 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4327 * it with the single Node @val
4328 *
4329 * Returns the newly created object.
4330 */
4331xmlXPathObjectPtr
4332xmlXPathNewNodeSet(xmlNodePtr val) {
4333 xmlXPathObjectPtr ret;
4334
4335 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4336 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004337 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004338 return(NULL);
4339 }
4340 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4341 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004342 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004343 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004344 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004345#ifdef XP_DEBUG_OBJ_USAGE
4346 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4347#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004348 return(ret);
4349}
4350
4351/**
4352 * xmlXPathNewValueTree:
4353 * @val: the NodePtr value
4354 *
4355 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4356 * it with the tree root @val
4357 *
4358 * Returns the newly created object.
4359 */
4360xmlXPathObjectPtr
4361xmlXPathNewValueTree(xmlNodePtr val) {
4362 xmlXPathObjectPtr ret;
4363
4364 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4365 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004366 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004367 return(NULL);
4368 }
4369 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4370 ret->type = XPATH_XSLT_TREE;
Brian C. Young98b451b2017-04-03 12:54:00 -07004371 ret->boolval = 0;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004372 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004373 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004374#ifdef XP_DEBUG_OBJ_USAGE
4375 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4376#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004377 return(ret);
4378}
4379
4380/**
4381 * xmlXPathNewNodeSetList:
4382 * @val: an existing NodeSet
4383 *
4384 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4385 * it with the Nodeset @val
4386 *
4387 * Returns the newly created object.
4388 */
4389xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004390xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4391{
Owen Taylor3473f882001-02-23 17:55:21 +00004392 xmlXPathObjectPtr ret;
4393 int i;
4394
4395 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004396 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004397 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004398 ret = xmlXPathNewNodeSet(NULL);
4399 else {
4400 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004401 if (ret) {
4402 for (i = 1; i < val->nodeNr; ++i) {
4403 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4404 < 0) break;
4405 }
4406 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004407 }
Owen Taylor3473f882001-02-23 17:55:21 +00004408
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004409 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004410}
4411
4412/**
4413 * xmlXPathWrapNodeSet:
4414 * @val: the NodePtr value
4415 *
4416 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4417 *
4418 * Returns the newly created object.
4419 */
4420xmlXPathObjectPtr
4421xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4422 xmlXPathObjectPtr ret;
4423
4424 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4425 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004426 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004427 return(NULL);
4428 }
4429 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4430 ret->type = XPATH_NODESET;
4431 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004432#ifdef XP_DEBUG_OBJ_USAGE
4433 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4434#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004435 return(ret);
4436}
4437
4438/**
4439 * xmlXPathFreeNodeSetList:
4440 * @obj: an existing NodeSetList object
4441 *
4442 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4443 * the list contrary to xmlXPathFreeObject().
4444 */
4445void
4446xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4447 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004448#ifdef XP_DEBUG_OBJ_USAGE
4449 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4450#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004451 xmlFree(obj);
4452}
4453
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004454/**
4455 * xmlXPathDifference:
4456 * @nodes1: a node-set
4457 * @nodes2: a node-set
4458 *
4459 * Implements the EXSLT - Sets difference() function:
4460 * node-set set:difference (node-set, node-set)
4461 *
4462 * Returns the difference between the two node sets, or nodes1 if
4463 * nodes2 is empty
4464 */
4465xmlNodeSetPtr
4466xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4467 xmlNodeSetPtr ret;
4468 int i, l1;
4469 xmlNodePtr cur;
4470
4471 if (xmlXPathNodeSetIsEmpty(nodes2))
4472 return(nodes1);
4473
4474 ret = xmlXPathNodeSetCreate(NULL);
4475 if (xmlXPathNodeSetIsEmpty(nodes1))
4476 return(ret);
4477
4478 l1 = xmlXPathNodeSetGetLength(nodes1);
4479
4480 for (i = 0; i < l1; i++) {
4481 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004482 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4483 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4484 break;
4485 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004486 }
4487 return(ret);
4488}
4489
4490/**
4491 * xmlXPathIntersection:
4492 * @nodes1: a node-set
4493 * @nodes2: a node-set
4494 *
4495 * Implements the EXSLT - Sets intersection() function:
4496 * node-set set:intersection (node-set, node-set)
4497 *
4498 * Returns a node set comprising the nodes that are within both the
4499 * node sets passed as arguments
4500 */
4501xmlNodeSetPtr
4502xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4503 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4504 int i, l1;
4505 xmlNodePtr cur;
4506
Daniel Veillardf88d8492008-04-01 08:00:31 +00004507 if (ret == NULL)
4508 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004509 if (xmlXPathNodeSetIsEmpty(nodes1))
4510 return(ret);
4511 if (xmlXPathNodeSetIsEmpty(nodes2))
4512 return(ret);
4513
4514 l1 = xmlXPathNodeSetGetLength(nodes1);
4515
4516 for (i = 0; i < l1; i++) {
4517 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004518 if (xmlXPathNodeSetContains(nodes2, cur)) {
4519 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4520 break;
4521 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004522 }
4523 return(ret);
4524}
4525
4526/**
4527 * xmlXPathDistinctSorted:
4528 * @nodes: a node-set, sorted by document order
4529 *
4530 * Implements the EXSLT - Sets distinct() function:
4531 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004532 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004533 * Returns a subset of the nodes contained in @nodes, or @nodes if
4534 * it is empty
4535 */
4536xmlNodeSetPtr
4537xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4538 xmlNodeSetPtr ret;
4539 xmlHashTablePtr hash;
4540 int i, l;
4541 xmlChar * strval;
4542 xmlNodePtr cur;
4543
4544 if (xmlXPathNodeSetIsEmpty(nodes))
4545 return(nodes);
4546
4547 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004548 if (ret == NULL)
4549 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004550 l = xmlXPathNodeSetGetLength(nodes);
4551 hash = xmlHashCreate (l);
4552 for (i = 0; i < l; i++) {
4553 cur = xmlXPathNodeSetItem(nodes, i);
4554 strval = xmlXPathCastNodeToString(cur);
4555 if (xmlHashLookup(hash, strval) == NULL) {
4556 xmlHashAddEntry(hash, strval, strval);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004557 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4558 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004559 } else {
4560 xmlFree(strval);
4561 }
4562 }
4563 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4564 return(ret);
4565}
4566
4567/**
4568 * xmlXPathDistinct:
4569 * @nodes: a node-set
4570 *
4571 * Implements the EXSLT - Sets distinct() function:
4572 * node-set set:distinct (node-set)
4573 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4574 * is called with the sorted node-set
4575 *
4576 * Returns a subset of the nodes contained in @nodes, or @nodes if
4577 * it is empty
4578 */
4579xmlNodeSetPtr
4580xmlXPathDistinct (xmlNodeSetPtr nodes) {
4581 if (xmlXPathNodeSetIsEmpty(nodes))
4582 return(nodes);
4583
4584 xmlXPathNodeSetSort(nodes);
4585 return(xmlXPathDistinctSorted(nodes));
4586}
4587
4588/**
4589 * xmlXPathHasSameNodes:
4590 * @nodes1: a node-set
4591 * @nodes2: a node-set
4592 *
4593 * Implements the EXSLT - Sets has-same-nodes function:
4594 * boolean set:has-same-node(node-set, node-set)
4595 *
4596 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4597 * otherwise
4598 */
4599int
4600xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4601 int i, l;
4602 xmlNodePtr cur;
4603
4604 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4605 xmlXPathNodeSetIsEmpty(nodes2))
4606 return(0);
4607
4608 l = xmlXPathNodeSetGetLength(nodes1);
4609 for (i = 0; i < l; i++) {
4610 cur = xmlXPathNodeSetItem(nodes1, i);
4611 if (xmlXPathNodeSetContains(nodes2, cur))
4612 return(1);
4613 }
4614 return(0);
4615}
4616
4617/**
4618 * xmlXPathNodeLeadingSorted:
4619 * @nodes: a node-set, sorted by document order
4620 * @node: a node
4621 *
4622 * Implements the EXSLT - Sets leading() function:
4623 * node-set set:leading (node-set, node-set)
4624 *
4625 * Returns the nodes in @nodes that precede @node in document order,
4626 * @nodes if @node is NULL or an empty node-set if @nodes
4627 * doesn't contain @node
4628 */
4629xmlNodeSetPtr
4630xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4631 int i, l;
4632 xmlNodePtr cur;
4633 xmlNodeSetPtr ret;
4634
4635 if (node == NULL)
4636 return(nodes);
4637
4638 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004639 if (ret == NULL)
4640 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004641 if (xmlXPathNodeSetIsEmpty(nodes) ||
4642 (!xmlXPathNodeSetContains(nodes, node)))
4643 return(ret);
4644
4645 l = xmlXPathNodeSetGetLength(nodes);
4646 for (i = 0; i < l; i++) {
4647 cur = xmlXPathNodeSetItem(nodes, i);
4648 if (cur == node)
4649 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004650 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4651 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004652 }
4653 return(ret);
4654}
4655
4656/**
4657 * xmlXPathNodeLeading:
4658 * @nodes: a node-set
4659 * @node: a node
4660 *
4661 * Implements the EXSLT - Sets leading() function:
4662 * node-set set:leading (node-set, node-set)
4663 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4664 * is called.
4665 *
4666 * Returns the nodes in @nodes that precede @node in document order,
4667 * @nodes if @node is NULL or an empty node-set if @nodes
4668 * doesn't contain @node
4669 */
4670xmlNodeSetPtr
4671xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4672 xmlXPathNodeSetSort(nodes);
4673 return(xmlXPathNodeLeadingSorted(nodes, node));
4674}
4675
4676/**
4677 * xmlXPathLeadingSorted:
4678 * @nodes1: a node-set, sorted by document order
4679 * @nodes2: a node-set, sorted by document order
4680 *
4681 * Implements the EXSLT - Sets leading() function:
4682 * node-set set:leading (node-set, node-set)
4683 *
4684 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4685 * in document order, @nodes1 if @nodes2 is NULL or empty or
4686 * an empty node-set if @nodes1 doesn't contain @nodes2
4687 */
4688xmlNodeSetPtr
4689xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4690 if (xmlXPathNodeSetIsEmpty(nodes2))
4691 return(nodes1);
4692 return(xmlXPathNodeLeadingSorted(nodes1,
4693 xmlXPathNodeSetItem(nodes2, 1)));
4694}
4695
4696/**
4697 * xmlXPathLeading:
4698 * @nodes1: a node-set
4699 * @nodes2: a node-set
4700 *
4701 * Implements the EXSLT - Sets leading() function:
4702 * node-set set:leading (node-set, node-set)
4703 * @nodes1 and @nodes2 are sorted by document order, then
4704 * #exslSetsLeadingSorted is called.
4705 *
4706 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4707 * in document order, @nodes1 if @nodes2 is NULL or empty or
4708 * an empty node-set if @nodes1 doesn't contain @nodes2
4709 */
4710xmlNodeSetPtr
4711xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4712 if (xmlXPathNodeSetIsEmpty(nodes2))
4713 return(nodes1);
4714 if (xmlXPathNodeSetIsEmpty(nodes1))
4715 return(xmlXPathNodeSetCreate(NULL));
4716 xmlXPathNodeSetSort(nodes1);
4717 xmlXPathNodeSetSort(nodes2);
4718 return(xmlXPathNodeLeadingSorted(nodes1,
4719 xmlXPathNodeSetItem(nodes2, 1)));
4720}
4721
4722/**
4723 * xmlXPathNodeTrailingSorted:
4724 * @nodes: a node-set, sorted by document order
4725 * @node: a node
4726 *
4727 * Implements the EXSLT - Sets trailing() function:
4728 * node-set set:trailing (node-set, node-set)
4729 *
4730 * Returns the nodes in @nodes that follow @node in document order,
4731 * @nodes if @node is NULL or an empty node-set if @nodes
4732 * doesn't contain @node
4733 */
4734xmlNodeSetPtr
4735xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4736 int i, l;
4737 xmlNodePtr cur;
4738 xmlNodeSetPtr ret;
4739
4740 if (node == NULL)
4741 return(nodes);
4742
4743 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004744 if (ret == NULL)
4745 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004746 if (xmlXPathNodeSetIsEmpty(nodes) ||
4747 (!xmlXPathNodeSetContains(nodes, node)))
4748 return(ret);
4749
4750 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004751 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004752 cur = xmlXPathNodeSetItem(nodes, i);
4753 if (cur == node)
4754 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004755 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4756 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004757 }
William M. Brack97ac8192007-06-06 17:19:24 +00004758 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004759 return(ret);
4760}
4761
4762/**
4763 * xmlXPathNodeTrailing:
4764 * @nodes: a node-set
4765 * @node: a node
4766 *
4767 * Implements the EXSLT - Sets trailing() function:
4768 * node-set set:trailing (node-set, node-set)
4769 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4770 * is called.
4771 *
4772 * Returns the nodes in @nodes that follow @node in document order,
4773 * @nodes if @node is NULL or an empty node-set if @nodes
4774 * doesn't contain @node
4775 */
4776xmlNodeSetPtr
4777xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4778 xmlXPathNodeSetSort(nodes);
4779 return(xmlXPathNodeTrailingSorted(nodes, node));
4780}
4781
4782/**
4783 * xmlXPathTrailingSorted:
4784 * @nodes1: a node-set, sorted by document order
4785 * @nodes2: a node-set, sorted by document order
4786 *
4787 * Implements the EXSLT - Sets trailing() function:
4788 * node-set set:trailing (node-set, node-set)
4789 *
4790 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4791 * in document order, @nodes1 if @nodes2 is NULL or empty or
4792 * an empty node-set if @nodes1 doesn't contain @nodes2
4793 */
4794xmlNodeSetPtr
4795xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4796 if (xmlXPathNodeSetIsEmpty(nodes2))
4797 return(nodes1);
4798 return(xmlXPathNodeTrailingSorted(nodes1,
4799 xmlXPathNodeSetItem(nodes2, 0)));
4800}
4801
4802/**
4803 * xmlXPathTrailing:
4804 * @nodes1: a node-set
4805 * @nodes2: a node-set
4806 *
4807 * Implements the EXSLT - Sets trailing() function:
4808 * node-set set:trailing (node-set, node-set)
4809 * @nodes1 and @nodes2 are sorted by document order, then
4810 * #xmlXPathTrailingSorted is called.
4811 *
4812 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4813 * in document order, @nodes1 if @nodes2 is NULL or empty or
4814 * an empty node-set if @nodes1 doesn't contain @nodes2
4815 */
4816xmlNodeSetPtr
4817xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4818 if (xmlXPathNodeSetIsEmpty(nodes2))
4819 return(nodes1);
4820 if (xmlXPathNodeSetIsEmpty(nodes1))
4821 return(xmlXPathNodeSetCreate(NULL));
4822 xmlXPathNodeSetSort(nodes1);
4823 xmlXPathNodeSetSort(nodes2);
4824 return(xmlXPathNodeTrailingSorted(nodes1,
4825 xmlXPathNodeSetItem(nodes2, 0)));
4826}
4827
Owen Taylor3473f882001-02-23 17:55:21 +00004828/************************************************************************
4829 * *
4830 * Routines to handle extra functions *
4831 * *
4832 ************************************************************************/
4833
4834/**
4835 * xmlXPathRegisterFunc:
4836 * @ctxt: the XPath context
4837 * @name: the function name
4838 * @f: the function implementation or NULL
4839 *
4840 * Register a new function. If @f is NULL it unregisters the function
4841 *
4842 * Returns 0 in case of success, -1 in case of error
4843 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004844int
Owen Taylor3473f882001-02-23 17:55:21 +00004845xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4846 xmlXPathFunction f) {
4847 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4848}
4849
4850/**
4851 * xmlXPathRegisterFuncNS:
4852 * @ctxt: the XPath context
4853 * @name: the function name
4854 * @ns_uri: the function namespace URI
4855 * @f: the function implementation or NULL
4856 *
4857 * Register a new function. If @f is NULL it unregisters the function
4858 *
4859 * Returns 0 in case of success, -1 in case of error
4860 */
4861int
4862xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4863 const xmlChar *ns_uri, xmlXPathFunction f) {
4864 if (ctxt == NULL)
4865 return(-1);
4866 if (name == NULL)
4867 return(-1);
4868
4869 if (ctxt->funcHash == NULL)
4870 ctxt->funcHash = xmlHashCreate(0);
4871 if (ctxt->funcHash == NULL)
4872 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004873 if (f == NULL)
4874 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004875 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004876}
4877
4878/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004879 * xmlXPathRegisterFuncLookup:
4880 * @ctxt: the XPath context
4881 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004882 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004883 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004884 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004885 */
4886void
4887xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4888 xmlXPathFuncLookupFunc f,
4889 void *funcCtxt) {
4890 if (ctxt == NULL)
4891 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004892 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004893 ctxt->funcLookupData = funcCtxt;
4894}
4895
4896/**
Owen Taylor3473f882001-02-23 17:55:21 +00004897 * xmlXPathFunctionLookup:
4898 * @ctxt: the XPath context
4899 * @name: the function name
4900 *
4901 * Search in the Function array of the context for the given
4902 * function.
4903 *
4904 * Returns the xmlXPathFunction or NULL if not found
4905 */
4906xmlXPathFunction
4907xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004908 if (ctxt == NULL)
4909 return (NULL);
4910
4911 if (ctxt->funcLookupFunc != NULL) {
4912 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004913 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004914
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004915 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004916 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004917 if (ret != NULL)
4918 return(ret);
4919 }
Owen Taylor3473f882001-02-23 17:55:21 +00004920 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4921}
4922
4923/**
4924 * xmlXPathFunctionLookupNS:
4925 * @ctxt: the XPath context
4926 * @name: the function name
4927 * @ns_uri: the function namespace URI
4928 *
4929 * Search in the Function array of the context for the given
4930 * function.
4931 *
4932 * Returns the xmlXPathFunction or NULL if not found
4933 */
4934xmlXPathFunction
4935xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4936 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004937 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004938
Owen Taylor3473f882001-02-23 17:55:21 +00004939 if (ctxt == NULL)
4940 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004941 if (name == NULL)
4942 return(NULL);
4943
Thomas Broyerba4ad322001-07-26 16:55:21 +00004944 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004945 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004946
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004947 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004948 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004949 if (ret != NULL)
4950 return(ret);
4951 }
4952
4953 if (ctxt->funcHash == NULL)
4954 return(NULL);
4955
William M. Brackad0e67c2004-12-01 14:35:10 +00004956 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4957 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004958}
4959
4960/**
4961 * xmlXPathRegisteredFuncsCleanup:
4962 * @ctxt: the XPath context
4963 *
4964 * Cleanup the XPath context data associated to registered functions
4965 */
4966void
4967xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4968 if (ctxt == NULL)
4969 return;
4970
4971 xmlHashFree(ctxt->funcHash, NULL);
4972 ctxt->funcHash = NULL;
4973}
4974
4975/************************************************************************
4976 * *
William M. Brack08171912003-12-29 02:52:11 +00004977 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004978 * *
4979 ************************************************************************/
4980
4981/**
4982 * xmlXPathRegisterVariable:
4983 * @ctxt: the XPath context
4984 * @name: the variable name
4985 * @value: the variable value or NULL
4986 *
4987 * Register a new variable value. If @value is NULL it unregisters
4988 * the variable
4989 *
4990 * Returns 0 in case of success, -1 in case of error
4991 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004992int
Owen Taylor3473f882001-02-23 17:55:21 +00004993xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4994 xmlXPathObjectPtr value) {
4995 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4996}
4997
4998/**
4999 * xmlXPathRegisterVariableNS:
5000 * @ctxt: the XPath context
5001 * @name: the variable name
5002 * @ns_uri: the variable namespace URI
5003 * @value: the variable value or NULL
5004 *
5005 * Register a new variable value. If @value is NULL it unregisters
5006 * the variable
5007 *
5008 * Returns 0 in case of success, -1 in case of error
5009 */
5010int
5011xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5012 const xmlChar *ns_uri,
5013 xmlXPathObjectPtr value) {
5014 if (ctxt == NULL)
5015 return(-1);
5016 if (name == NULL)
5017 return(-1);
5018
5019 if (ctxt->varHash == NULL)
5020 ctxt->varHash = xmlHashCreate(0);
5021 if (ctxt->varHash == NULL)
5022 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00005023 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005024 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00005025 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00005026 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5027 (void *) value,
5028 (xmlHashDeallocator)xmlXPathFreeObject));
5029}
5030
5031/**
5032 * xmlXPathRegisterVariableLookup:
5033 * @ctxt: the XPath context
5034 * @f: the lookup function
5035 * @data: the lookup data
5036 *
5037 * register an external mechanism to do variable lookup
5038 */
5039void
5040xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5041 xmlXPathVariableLookupFunc f, void *data) {
5042 if (ctxt == NULL)
5043 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00005044 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00005045 ctxt->varLookupData = data;
5046}
5047
5048/**
5049 * xmlXPathVariableLookup:
5050 * @ctxt: the XPath context
5051 * @name: the variable name
5052 *
5053 * Search in the Variable array of the context for the given
5054 * variable value.
5055 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005056 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005057 */
5058xmlXPathObjectPtr
5059xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5060 if (ctxt == NULL)
5061 return(NULL);
5062
5063 if (ctxt->varLookupFunc != NULL) {
5064 xmlXPathObjectPtr ret;
5065
5066 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5067 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00005068 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005069 }
5070 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5071}
5072
5073/**
5074 * xmlXPathVariableLookupNS:
5075 * @ctxt: the XPath context
5076 * @name: the variable name
5077 * @ns_uri: the variable namespace URI
5078 *
5079 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005080 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005081 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005082 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005083 */
5084xmlXPathObjectPtr
5085xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5086 const xmlChar *ns_uri) {
5087 if (ctxt == NULL)
5088 return(NULL);
5089
5090 if (ctxt->varLookupFunc != NULL) {
5091 xmlXPathObjectPtr ret;
5092
5093 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5094 (ctxt->varLookupData, name, ns_uri);
5095 if (ret != NULL) return(ret);
5096 }
5097
5098 if (ctxt->varHash == NULL)
5099 return(NULL);
5100 if (name == NULL)
5101 return(NULL);
5102
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005103 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005104 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005105}
5106
5107/**
5108 * xmlXPathRegisteredVariablesCleanup:
5109 * @ctxt: the XPath context
5110 *
5111 * Cleanup the XPath context data associated to registered variables
5112 */
5113void
5114xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5115 if (ctxt == NULL)
5116 return;
5117
Daniel Veillard76d66f42001-05-16 21:05:17 +00005118 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005119 ctxt->varHash = NULL;
5120}
5121
5122/**
5123 * xmlXPathRegisterNs:
5124 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005125 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005126 * @ns_uri: the namespace name
5127 *
5128 * Register a new namespace. If @ns_uri is NULL it unregisters
5129 * the namespace
5130 *
5131 * Returns 0 in case of success, -1 in case of error
5132 */
5133int
5134xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5135 const xmlChar *ns_uri) {
5136 if (ctxt == NULL)
5137 return(-1);
5138 if (prefix == NULL)
5139 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005140 if (prefix[0] == 0)
5141 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005142
5143 if (ctxt->nsHash == NULL)
5144 ctxt->nsHash = xmlHashCreate(10);
5145 if (ctxt->nsHash == NULL)
5146 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005147 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005148 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005149 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005150 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005151 (xmlHashDeallocator)xmlFree));
5152}
5153
5154/**
5155 * xmlXPathNsLookup:
5156 * @ctxt: the XPath context
5157 * @prefix: the namespace prefix value
5158 *
5159 * Search in the namespace declaration array of the context for the given
5160 * namespace name associated to the given prefix
5161 *
5162 * Returns the value or NULL if not found
5163 */
5164const xmlChar *
5165xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5166 if (ctxt == NULL)
5167 return(NULL);
5168 if (prefix == NULL)
5169 return(NULL);
5170
5171#ifdef XML_XML_NAMESPACE
5172 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5173 return(XML_XML_NAMESPACE);
5174#endif
5175
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005176 if (ctxt->namespaces != NULL) {
5177 int i;
5178
5179 for (i = 0;i < ctxt->nsNr;i++) {
5180 if ((ctxt->namespaces[i] != NULL) &&
5181 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5182 return(ctxt->namespaces[i]->href);
5183 }
5184 }
Owen Taylor3473f882001-02-23 17:55:21 +00005185
5186 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5187}
5188
5189/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005190 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005191 * @ctxt: the XPath context
5192 *
5193 * Cleanup the XPath context data associated to registered variables
5194 */
5195void
5196xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5197 if (ctxt == NULL)
5198 return;
5199
Daniel Veillard42766c02002-08-22 20:52:17 +00005200 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005201 ctxt->nsHash = NULL;
5202}
5203
5204/************************************************************************
5205 * *
5206 * Routines to handle Values *
5207 * *
5208 ************************************************************************/
5209
William M. Brack08171912003-12-29 02:52:11 +00005210/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005211
5212/**
5213 * xmlXPathNewFloat:
5214 * @val: the double value
5215 *
5216 * Create a new xmlXPathObjectPtr of type double and of value @val
5217 *
5218 * Returns the newly created object.
5219 */
5220xmlXPathObjectPtr
5221xmlXPathNewFloat(double val) {
5222 xmlXPathObjectPtr ret;
5223
5224 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5225 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005226 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005227 return(NULL);
5228 }
5229 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5230 ret->type = XPATH_NUMBER;
5231 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005232#ifdef XP_DEBUG_OBJ_USAGE
5233 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5234#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005235 return(ret);
5236}
5237
5238/**
5239 * xmlXPathNewBoolean:
5240 * @val: the boolean value
5241 *
5242 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5243 *
5244 * Returns the newly created object.
5245 */
5246xmlXPathObjectPtr
5247xmlXPathNewBoolean(int val) {
5248 xmlXPathObjectPtr ret;
5249
5250 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5251 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005252 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005253 return(NULL);
5254 }
5255 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5256 ret->type = XPATH_BOOLEAN;
5257 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005258#ifdef XP_DEBUG_OBJ_USAGE
5259 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5260#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005261 return(ret);
5262}
5263
5264/**
5265 * xmlXPathNewString:
5266 * @val: the xmlChar * value
5267 *
5268 * Create a new xmlXPathObjectPtr of type string and of value @val
5269 *
5270 * Returns the newly created object.
5271 */
5272xmlXPathObjectPtr
5273xmlXPathNewString(const xmlChar *val) {
5274 xmlXPathObjectPtr ret;
5275
5276 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5277 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005278 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005279 return(NULL);
5280 }
5281 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5282 ret->type = XPATH_STRING;
5283 if (val != NULL)
5284 ret->stringval = xmlStrdup(val);
5285 else
5286 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005287#ifdef XP_DEBUG_OBJ_USAGE
5288 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5289#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005290 return(ret);
5291}
5292
5293/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005294 * xmlXPathWrapString:
5295 * @val: the xmlChar * value
5296 *
5297 * Wraps the @val string into an XPath object.
5298 *
5299 * Returns the newly created object.
5300 */
5301xmlXPathObjectPtr
5302xmlXPathWrapString (xmlChar *val) {
5303 xmlXPathObjectPtr ret;
5304
5305 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5306 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005307 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005308 return(NULL);
5309 }
5310 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5311 ret->type = XPATH_STRING;
5312 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005313#ifdef XP_DEBUG_OBJ_USAGE
5314 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5315#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005316 return(ret);
5317}
5318
5319/**
Owen Taylor3473f882001-02-23 17:55:21 +00005320 * xmlXPathNewCString:
5321 * @val: the char * value
5322 *
5323 * Create a new xmlXPathObjectPtr of type string and of value @val
5324 *
5325 * Returns the newly created object.
5326 */
5327xmlXPathObjectPtr
5328xmlXPathNewCString(const char *val) {
5329 xmlXPathObjectPtr ret;
5330
5331 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5332 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005333 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005334 return(NULL);
5335 }
5336 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5337 ret->type = XPATH_STRING;
5338 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005339#ifdef XP_DEBUG_OBJ_USAGE
5340 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5341#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005342 return(ret);
5343}
5344
5345/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005346 * xmlXPathWrapCString:
5347 * @val: the char * value
5348 *
5349 * Wraps a string into an XPath object.
5350 *
5351 * Returns the newly created object.
5352 */
5353xmlXPathObjectPtr
5354xmlXPathWrapCString (char * val) {
5355 return(xmlXPathWrapString((xmlChar *)(val)));
5356}
5357
5358/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005359 * xmlXPathWrapExternal:
5360 * @val: the user data
5361 *
5362 * Wraps the @val data into an XPath object.
5363 *
5364 * Returns the newly created object.
5365 */
5366xmlXPathObjectPtr
5367xmlXPathWrapExternal (void *val) {
5368 xmlXPathObjectPtr ret;
5369
5370 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5371 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005372 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005373 return(NULL);
5374 }
5375 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5376 ret->type = XPATH_USERS;
5377 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005378#ifdef XP_DEBUG_OBJ_USAGE
5379 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5380#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005381 return(ret);
5382}
5383
5384/**
Owen Taylor3473f882001-02-23 17:55:21 +00005385 * xmlXPathObjectCopy:
5386 * @val: the original object
5387 *
5388 * allocate a new copy of a given object
5389 *
5390 * Returns the newly created object.
5391 */
5392xmlXPathObjectPtr
5393xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5394 xmlXPathObjectPtr ret;
5395
5396 if (val == NULL)
5397 return(NULL);
5398
5399 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5400 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005401 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005402 return(NULL);
5403 }
5404 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005405#ifdef XP_DEBUG_OBJ_USAGE
5406 xmlXPathDebugObjUsageRequested(NULL, val->type);
5407#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005408 switch (val->type) {
5409 case XPATH_BOOLEAN:
5410 case XPATH_NUMBER:
5411 case XPATH_POINT:
5412 case XPATH_RANGE:
5413 break;
5414 case XPATH_STRING:
5415 ret->stringval = xmlStrdup(val->stringval);
5416 break;
5417 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005418#if 0
5419/*
5420 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5421 this previous handling is no longer correct, and can cause some serious
5422 problems (ref. bug 145547)
5423*/
Owen Taylor3473f882001-02-23 17:55:21 +00005424 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005425 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005426 xmlNodePtr cur, tmp;
5427 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005428
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005429 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005430 top = xmlNewDoc(NULL);
5431 top->name = (char *)
5432 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005433 ret->user = top;
5434 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005435 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005436 cur = val->nodesetval->nodeTab[0]->children;
5437 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005438 tmp = xmlDocCopyNode(cur, top, 1);
5439 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005440 cur = cur->next;
5441 }
5442 }
William M. Bracke9449c52004-07-11 14:41:20 +00005443
Daniel Veillard9adc0462003-03-24 18:39:54 +00005444 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005445 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005446 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005447 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005448 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005449#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005450 case XPATH_NODESET:
5451 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005452 /* Do not deallocate the copied tree value */
5453 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005454 break;
5455 case XPATH_LOCATIONSET:
5456#ifdef LIBXML_XPTR_ENABLED
5457 {
5458 xmlLocationSetPtr loc = val->user;
5459 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5460 break;
5461 }
5462#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005463 case XPATH_USERS:
5464 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005465 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005466 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005467 xmlGenericError(xmlGenericErrorContext,
5468 "xmlXPathObjectCopy: unsupported type %d\n",
5469 val->type);
5470 break;
5471 }
5472 return(ret);
5473}
5474
5475/**
5476 * xmlXPathFreeObject:
5477 * @obj: the object to free
5478 *
5479 * Free up an xmlXPathObjectPtr object.
5480 */
5481void
5482xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5483 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005484 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005485 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005486#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005487 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005488 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005489 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005490 } else
5491#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005492 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005493 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005494 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005495 } else {
5496 if (obj->nodesetval != NULL)
5497 xmlXPathFreeNodeSet(obj->nodesetval);
5498 }
Owen Taylor3473f882001-02-23 17:55:21 +00005499#ifdef LIBXML_XPTR_ENABLED
5500 } else if (obj->type == XPATH_LOCATIONSET) {
5501 if (obj->user != NULL)
5502 xmlXPtrFreeLocationSet(obj->user);
5503#endif
5504 } else if (obj->type == XPATH_STRING) {
5505 if (obj->stringval != NULL)
5506 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005507 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005508#ifdef XP_DEBUG_OBJ_USAGE
5509 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5510#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005511 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005512}
Owen Taylor3473f882001-02-23 17:55:21 +00005513
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005514/**
5515 * xmlXPathReleaseObject:
5516 * @obj: the xmlXPathObjectPtr to free or to cache
5517 *
5518 * Depending on the state of the cache this frees the given
5519 * XPath object or stores it in the cache.
5520 */
5521static void
5522xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5523{
5524#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5525 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5526 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5527
5528#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5529
5530 if (obj == NULL)
5531 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005532 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005533 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005534 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005535 xmlXPathContextCachePtr cache =
5536 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005537
5538 switch (obj->type) {
5539 case XPATH_NODESET:
5540 case XPATH_XSLT_TREE:
5541 if (obj->nodesetval != NULL) {
5542 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005543 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005544 * It looks like the @boolval is used for
5545 * evaluation if this an XSLT Result Tree Fragment.
5546 * TODO: Check if this assumption is correct.
5547 */
5548 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5549 xmlXPathFreeValueTree(obj->nodesetval);
5550 obj->nodesetval = NULL;
5551 } else if ((obj->nodesetval->nodeMax <= 40) &&
5552 (XP_CACHE_WANTS(cache->nodesetObjs,
5553 cache->maxNodeset)))
5554 {
5555 XP_CACHE_ADD(cache->nodesetObjs, obj);
5556 goto obj_cached;
5557 } else {
5558 xmlXPathFreeNodeSet(obj->nodesetval);
5559 obj->nodesetval = NULL;
5560 }
5561 }
5562 break;
5563 case XPATH_STRING:
5564 if (obj->stringval != NULL)
5565 xmlFree(obj->stringval);
5566
5567 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5568 XP_CACHE_ADD(cache->stringObjs, obj);
5569 goto obj_cached;
5570 }
5571 break;
5572 case XPATH_BOOLEAN:
5573 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5574 XP_CACHE_ADD(cache->booleanObjs, obj);
5575 goto obj_cached;
5576 }
5577 break;
5578 case XPATH_NUMBER:
5579 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5580 XP_CACHE_ADD(cache->numberObjs, obj);
5581 goto obj_cached;
5582 }
5583 break;
5584#ifdef LIBXML_XPTR_ENABLED
5585 case XPATH_LOCATIONSET:
5586 if (obj->user != NULL) {
5587 xmlXPtrFreeLocationSet(obj->user);
5588 }
5589 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005590#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005591 default:
5592 goto free_obj;
5593 }
5594
5595 /*
5596 * Fallback to adding to the misc-objects slot.
5597 */
5598 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5599 XP_CACHE_ADD(cache->miscObjs, obj);
5600 } else
5601 goto free_obj;
5602
5603obj_cached:
5604
5605#ifdef XP_DEBUG_OBJ_USAGE
5606 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5607#endif
5608
5609 if (obj->nodesetval != NULL) {
5610 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005611
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005612 /*
5613 * TODO: Due to those nasty ns-nodes, we need to traverse
5614 * the list and free the ns-nodes.
5615 * URGENT TODO: Check if it's actually slowing things down.
5616 * Maybe we shouldn't try to preserve the list.
5617 */
5618 if (tmpset->nodeNr > 1) {
5619 int i;
5620 xmlNodePtr node;
5621
5622 for (i = 0; i < tmpset->nodeNr; i++) {
5623 node = tmpset->nodeTab[i];
5624 if ((node != NULL) &&
5625 (node->type == XML_NAMESPACE_DECL))
5626 {
5627 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5628 }
5629 }
5630 } else if (tmpset->nodeNr == 1) {
5631 if ((tmpset->nodeTab[0] != NULL) &&
5632 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5633 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005634 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005635 tmpset->nodeNr = 0;
5636 memset(obj, 0, sizeof(xmlXPathObject));
5637 obj->nodesetval = tmpset;
5638 } else
5639 memset(obj, 0, sizeof(xmlXPathObject));
5640
5641 return;
5642
5643free_obj:
5644 /*
5645 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005646 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005647 if (obj->nodesetval != NULL)
5648 xmlXPathFreeNodeSet(obj->nodesetval);
5649#ifdef XP_DEBUG_OBJ_USAGE
5650 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5651#endif
5652 xmlFree(obj);
5653 }
5654 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005655}
5656
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005657
5658/************************************************************************
5659 * *
5660 * Type Casting Routines *
5661 * *
5662 ************************************************************************/
5663
5664/**
5665 * xmlXPathCastBooleanToString:
5666 * @val: a boolean
5667 *
5668 * Converts a boolean to its string value.
5669 *
5670 * Returns a newly allocated string.
5671 */
5672xmlChar *
5673xmlXPathCastBooleanToString (int val) {
5674 xmlChar *ret;
5675 if (val)
5676 ret = xmlStrdup((const xmlChar *) "true");
5677 else
5678 ret = xmlStrdup((const xmlChar *) "false");
5679 return(ret);
5680}
5681
5682/**
5683 * xmlXPathCastNumberToString:
5684 * @val: a number
5685 *
5686 * Converts a number to its string value.
5687 *
5688 * Returns a newly allocated string.
5689 */
5690xmlChar *
5691xmlXPathCastNumberToString (double val) {
5692 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005693 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005694 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005695 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005696 break;
5697 case -1:
5698 ret = xmlStrdup((const xmlChar *) "-Infinity");
5699 break;
5700 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005701 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005702 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005703 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5704 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005705 } else {
5706 /* could be improved */
5707 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005708 xmlXPathFormatNumber(val, buf, 99);
5709 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005710 ret = xmlStrdup((const xmlChar *) buf);
5711 }
5712 }
5713 return(ret);
5714}
5715
5716/**
5717 * xmlXPathCastNodeToString:
5718 * @node: a node
5719 *
5720 * Converts a node to its string value.
5721 *
5722 * Returns a newly allocated string.
5723 */
5724xmlChar *
5725xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005726xmlChar *ret;
5727 if ((ret = xmlNodeGetContent(node)) == NULL)
5728 ret = xmlStrdup((const xmlChar *) "");
5729 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005730}
5731
5732/**
5733 * xmlXPathCastNodeSetToString:
5734 * @ns: a node-set
5735 *
5736 * Converts a node-set to its string value.
5737 *
5738 * Returns a newly allocated string.
5739 */
5740xmlChar *
5741xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5742 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5743 return(xmlStrdup((const xmlChar *) ""));
5744
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005745 if (ns->nodeNr > 1)
5746 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005747 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5748}
5749
5750/**
5751 * xmlXPathCastToString:
5752 * @val: an XPath object
5753 *
5754 * Converts an existing object to its string() equivalent
5755 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005756 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005757 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005758 */
5759xmlChar *
5760xmlXPathCastToString(xmlXPathObjectPtr val) {
5761 xmlChar *ret = NULL;
5762
5763 if (val == NULL)
5764 return(xmlStrdup((const xmlChar *) ""));
5765 switch (val->type) {
5766 case XPATH_UNDEFINED:
5767#ifdef DEBUG_EXPR
5768 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5769#endif
5770 ret = xmlStrdup((const xmlChar *) "");
5771 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005772 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005773 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005774 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5775 break;
5776 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005777 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005778 case XPATH_BOOLEAN:
5779 ret = xmlXPathCastBooleanToString(val->boolval);
5780 break;
5781 case XPATH_NUMBER: {
5782 ret = xmlXPathCastNumberToString(val->floatval);
5783 break;
5784 }
5785 case XPATH_USERS:
5786 case XPATH_POINT:
5787 case XPATH_RANGE:
5788 case XPATH_LOCATIONSET:
5789 TODO
5790 ret = xmlStrdup((const xmlChar *) "");
5791 break;
5792 }
5793 return(ret);
5794}
5795
5796/**
5797 * xmlXPathConvertString:
5798 * @val: an XPath object
5799 *
5800 * Converts an existing object to its string() equivalent
5801 *
5802 * Returns the new object, the old one is freed (or the operation
5803 * is done directly on @val)
5804 */
5805xmlXPathObjectPtr
5806xmlXPathConvertString(xmlXPathObjectPtr val) {
5807 xmlChar *res = NULL;
5808
5809 if (val == NULL)
5810 return(xmlXPathNewCString(""));
5811
5812 switch (val->type) {
5813 case XPATH_UNDEFINED:
5814#ifdef DEBUG_EXPR
5815 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5816#endif
5817 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005818 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005819 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005820 res = xmlXPathCastNodeSetToString(val->nodesetval);
5821 break;
5822 case XPATH_STRING:
5823 return(val);
5824 case XPATH_BOOLEAN:
5825 res = xmlXPathCastBooleanToString(val->boolval);
5826 break;
5827 case XPATH_NUMBER:
5828 res = xmlXPathCastNumberToString(val->floatval);
5829 break;
5830 case XPATH_USERS:
5831 case XPATH_POINT:
5832 case XPATH_RANGE:
5833 case XPATH_LOCATIONSET:
5834 TODO;
5835 break;
5836 }
5837 xmlXPathFreeObject(val);
5838 if (res == NULL)
5839 return(xmlXPathNewCString(""));
5840 return(xmlXPathWrapString(res));
5841}
5842
5843/**
5844 * xmlXPathCastBooleanToNumber:
5845 * @val: a boolean
5846 *
5847 * Converts a boolean to its number value
5848 *
5849 * Returns the number value
5850 */
5851double
5852xmlXPathCastBooleanToNumber(int val) {
5853 if (val)
5854 return(1.0);
5855 return(0.0);
5856}
5857
5858/**
5859 * xmlXPathCastStringToNumber:
5860 * @val: a string
5861 *
5862 * Converts a string to its number value
5863 *
5864 * Returns the number value
5865 */
5866double
5867xmlXPathCastStringToNumber(const xmlChar * val) {
5868 return(xmlXPathStringEvalNumber(val));
5869}
5870
5871/**
5872 * xmlXPathCastNodeToNumber:
5873 * @node: a node
5874 *
5875 * Converts a node to its number value
5876 *
5877 * Returns the number value
5878 */
5879double
5880xmlXPathCastNodeToNumber (xmlNodePtr node) {
5881 xmlChar *strval;
5882 double ret;
5883
5884 if (node == NULL)
5885 return(xmlXPathNAN);
5886 strval = xmlXPathCastNodeToString(node);
5887 if (strval == NULL)
5888 return(xmlXPathNAN);
5889 ret = xmlXPathCastStringToNumber(strval);
5890 xmlFree(strval);
5891
5892 return(ret);
5893}
5894
5895/**
5896 * xmlXPathCastNodeSetToNumber:
5897 * @ns: a node-set
5898 *
5899 * Converts a node-set to its number value
5900 *
5901 * Returns the number value
5902 */
5903double
5904xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5905 xmlChar *str;
5906 double ret;
5907
5908 if (ns == NULL)
5909 return(xmlXPathNAN);
5910 str = xmlXPathCastNodeSetToString(ns);
5911 ret = xmlXPathCastStringToNumber(str);
5912 xmlFree(str);
5913 return(ret);
5914}
5915
5916/**
5917 * xmlXPathCastToNumber:
5918 * @val: an XPath object
5919 *
5920 * Converts an XPath object to its number value
5921 *
5922 * Returns the number value
5923 */
5924double
5925xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5926 double ret = 0.0;
5927
5928 if (val == NULL)
5929 return(xmlXPathNAN);
5930 switch (val->type) {
5931 case XPATH_UNDEFINED:
5932#ifdef DEGUB_EXPR
5933 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5934#endif
5935 ret = xmlXPathNAN;
5936 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005937 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005938 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005939 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5940 break;
5941 case XPATH_STRING:
5942 ret = xmlXPathCastStringToNumber(val->stringval);
5943 break;
5944 case XPATH_NUMBER:
5945 ret = val->floatval;
5946 break;
5947 case XPATH_BOOLEAN:
5948 ret = xmlXPathCastBooleanToNumber(val->boolval);
5949 break;
5950 case XPATH_USERS:
5951 case XPATH_POINT:
5952 case XPATH_RANGE:
5953 case XPATH_LOCATIONSET:
5954 TODO;
5955 ret = xmlXPathNAN;
5956 break;
5957 }
5958 return(ret);
5959}
5960
5961/**
5962 * xmlXPathConvertNumber:
5963 * @val: an XPath object
5964 *
5965 * Converts an existing object to its number() equivalent
5966 *
5967 * Returns the new object, the old one is freed (or the operation
5968 * is done directly on @val)
5969 */
5970xmlXPathObjectPtr
5971xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5972 xmlXPathObjectPtr ret;
5973
5974 if (val == NULL)
5975 return(xmlXPathNewFloat(0.0));
5976 if (val->type == XPATH_NUMBER)
5977 return(val);
5978 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5979 xmlXPathFreeObject(val);
5980 return(ret);
5981}
5982
5983/**
5984 * xmlXPathCastNumberToBoolean:
5985 * @val: a number
5986 *
5987 * Converts a number to its boolean value
5988 *
5989 * Returns the boolean value
5990 */
5991int
5992xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005993 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005994 return(0);
5995 return(1);
5996}
5997
5998/**
5999 * xmlXPathCastStringToBoolean:
6000 * @val: a string
6001 *
6002 * Converts a string to its boolean value
6003 *
6004 * Returns the boolean value
6005 */
6006int
6007xmlXPathCastStringToBoolean (const xmlChar *val) {
6008 if ((val == NULL) || (xmlStrlen(val) == 0))
6009 return(0);
6010 return(1);
6011}
6012
6013/**
6014 * xmlXPathCastNodeSetToBoolean:
6015 * @ns: a node-set
6016 *
6017 * Converts a node-set to its boolean value
6018 *
6019 * Returns the boolean value
6020 */
6021int
6022xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6023 if ((ns == NULL) || (ns->nodeNr == 0))
6024 return(0);
6025 return(1);
6026}
6027
6028/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006029 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006030 * @val: an XPath object
6031 *
6032 * Converts an XPath object to its boolean value
6033 *
6034 * Returns the boolean value
6035 */
6036int
6037xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6038 int ret = 0;
6039
6040 if (val == NULL)
6041 return(0);
6042 switch (val->type) {
6043 case XPATH_UNDEFINED:
6044#ifdef DEBUG_EXPR
6045 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6046#endif
6047 ret = 0;
6048 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006049 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00006050 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006051 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6052 break;
6053 case XPATH_STRING:
6054 ret = xmlXPathCastStringToBoolean(val->stringval);
6055 break;
6056 case XPATH_NUMBER:
6057 ret = xmlXPathCastNumberToBoolean(val->floatval);
6058 break;
6059 case XPATH_BOOLEAN:
6060 ret = val->boolval;
6061 break;
6062 case XPATH_USERS:
6063 case XPATH_POINT:
6064 case XPATH_RANGE:
6065 case XPATH_LOCATIONSET:
6066 TODO;
6067 ret = 0;
6068 break;
6069 }
6070 return(ret);
6071}
6072
6073
6074/**
6075 * xmlXPathConvertBoolean:
6076 * @val: an XPath object
6077 *
6078 * Converts an existing object to its boolean() equivalent
6079 *
6080 * Returns the new object, the old one is freed (or the operation
6081 * is done directly on @val)
6082 */
6083xmlXPathObjectPtr
6084xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6085 xmlXPathObjectPtr ret;
6086
6087 if (val == NULL)
6088 return(xmlXPathNewBoolean(0));
6089 if (val->type == XPATH_BOOLEAN)
6090 return(val);
6091 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6092 xmlXPathFreeObject(val);
6093 return(ret);
6094}
6095
Owen Taylor3473f882001-02-23 17:55:21 +00006096/************************************************************************
6097 * *
6098 * Routines to handle XPath contexts *
6099 * *
6100 ************************************************************************/
6101
6102/**
6103 * xmlXPathNewContext:
6104 * @doc: the XML document
6105 *
6106 * Create a new xmlXPathContext
6107 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006108 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006109 */
6110xmlXPathContextPtr
6111xmlXPathNewContext(xmlDocPtr doc) {
6112 xmlXPathContextPtr ret;
6113
6114 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6115 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006116 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006117 return(NULL);
6118 }
6119 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6120 ret->doc = doc;
6121 ret->node = NULL;
6122
6123 ret->varHash = NULL;
6124
6125 ret->nb_types = 0;
6126 ret->max_types = 0;
6127 ret->types = NULL;
6128
6129 ret->funcHash = xmlHashCreate(0);
6130
6131 ret->nb_axis = 0;
6132 ret->max_axis = 0;
6133 ret->axis = NULL;
6134
6135 ret->nsHash = NULL;
6136 ret->user = NULL;
6137
6138 ret->contextSize = -1;
6139 ret->proximityPosition = -1;
6140
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006141#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006142 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006143 xmlXPathFreeContext(ret);
6144 return(NULL);
6145 }
6146#endif
6147
Daniel Veillard45490ae2008-07-29 09:13:19 +00006148 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006149
Owen Taylor3473f882001-02-23 17:55:21 +00006150 return(ret);
6151}
6152
6153/**
6154 * xmlXPathFreeContext:
6155 * @ctxt: the context to free
6156 *
6157 * Free up an xmlXPathContext
6158 */
6159void
6160xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006161 if (ctxt == NULL) return;
6162
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006163 if (ctxt->cache != NULL)
6164 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006165 xmlXPathRegisteredNsCleanup(ctxt);
6166 xmlXPathRegisteredFuncsCleanup(ctxt);
6167 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006168 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006169 xmlFree(ctxt);
6170}
6171
6172/************************************************************************
6173 * *
6174 * Routines to handle XPath parser contexts *
6175 * *
6176 ************************************************************************/
6177
6178#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006179 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006180 __xmlRaiseError(NULL, NULL, NULL, \
6181 NULL, NULL, XML_FROM_XPATH, \
6182 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6183 __FILE__, __LINE__, \
6184 NULL, NULL, NULL, 0, 0, \
6185 "NULL context pointer\n"); \
6186 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006187 } \
6188
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006189#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006190 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006191 __xmlRaiseError(NULL, NULL, NULL, \
6192 NULL, NULL, XML_FROM_XPATH, \
6193 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6194 __FILE__, __LINE__, \
6195 NULL, NULL, NULL, 0, 0, \
6196 "NULL context pointer\n"); \
6197 return(-1); \
6198 } \
6199
Owen Taylor3473f882001-02-23 17:55:21 +00006200
6201#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006202 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006203 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006204 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006205 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006206 }
Owen Taylor3473f882001-02-23 17:55:21 +00006207
6208
6209/**
6210 * xmlXPathNewParserContext:
6211 * @str: the XPath expression
6212 * @ctxt: the XPath context
6213 *
6214 * Create a new xmlXPathParserContext
6215 *
6216 * Returns the xmlXPathParserContext just allocated.
6217 */
6218xmlXPathParserContextPtr
6219xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6220 xmlXPathParserContextPtr ret;
6221
6222 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6223 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006224 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006225 return(NULL);
6226 }
6227 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6228 ret->cur = ret->base = str;
6229 ret->context = ctxt;
6230
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006231 ret->comp = xmlXPathNewCompExpr();
6232 if (ret->comp == NULL) {
6233 xmlFree(ret->valueTab);
6234 xmlFree(ret);
6235 return(NULL);
6236 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006237 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6238 ret->comp->dict = ctxt->dict;
6239 xmlDictReference(ret->comp->dict);
6240 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006241
6242 return(ret);
6243}
6244
6245/**
6246 * xmlXPathCompParserContext:
6247 * @comp: the XPath compiled expression
6248 * @ctxt: the XPath context
6249 *
6250 * Create a new xmlXPathParserContext when processing a compiled expression
6251 *
6252 * Returns the xmlXPathParserContext just allocated.
6253 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006254static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006255xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6256 xmlXPathParserContextPtr ret;
6257
6258 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6259 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006260 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006261 return(NULL);
6262 }
6263 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6264
Owen Taylor3473f882001-02-23 17:55:21 +00006265 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006266 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006267 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006268 if (ret->valueTab == NULL) {
6269 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006270 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006271 return(NULL);
6272 }
Owen Taylor3473f882001-02-23 17:55:21 +00006273 ret->valueNr = 0;
6274 ret->valueMax = 10;
6275 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006276 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006277
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006278 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006279 ret->comp = comp;
6280
Owen Taylor3473f882001-02-23 17:55:21 +00006281 return(ret);
6282}
6283
6284/**
6285 * xmlXPathFreeParserContext:
6286 * @ctxt: the context to free
6287 *
6288 * Free up an xmlXPathParserContext
6289 */
6290void
6291xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6292 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006293 xmlFree(ctxt->valueTab);
6294 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006295 if (ctxt->comp != NULL) {
6296#ifdef XPATH_STREAMING
6297 if (ctxt->comp->stream != NULL) {
6298 xmlFreePatternList(ctxt->comp->stream);
6299 ctxt->comp->stream = NULL;
6300 }
6301#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006302 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006303 }
Owen Taylor3473f882001-02-23 17:55:21 +00006304 xmlFree(ctxt);
6305}
6306
6307/************************************************************************
6308 * *
6309 * The implicit core function library *
6310 * *
6311 ************************************************************************/
6312
Owen Taylor3473f882001-02-23 17:55:21 +00006313/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006314 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006315 * @node: a node pointer
6316 *
6317 * Function computing the beginning of the string value of the node,
6318 * used to speed up comparisons
6319 *
6320 * Returns an int usable as a hash
6321 */
6322static unsigned int
6323xmlXPathNodeValHash(xmlNodePtr node) {
6324 int len = 2;
6325 const xmlChar * string = NULL;
6326 xmlNodePtr tmp = NULL;
6327 unsigned int ret = 0;
6328
6329 if (node == NULL)
6330 return(0);
6331
Daniel Veillard9adc0462003-03-24 18:39:54 +00006332 if (node->type == XML_DOCUMENT_NODE) {
6333 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6334 if (tmp == NULL)
6335 node = node->children;
6336 else
6337 node = tmp;
6338
6339 if (node == NULL)
6340 return(0);
6341 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006342
6343 switch (node->type) {
6344 case XML_COMMENT_NODE:
6345 case XML_PI_NODE:
6346 case XML_CDATA_SECTION_NODE:
6347 case XML_TEXT_NODE:
6348 string = node->content;
6349 if (string == NULL)
6350 return(0);
6351 if (string[0] == 0)
6352 return(0);
6353 return(((unsigned int) string[0]) +
6354 (((unsigned int) string[1]) << 8));
6355 case XML_NAMESPACE_DECL:
6356 string = ((xmlNsPtr)node)->href;
6357 if (string == NULL)
6358 return(0);
6359 if (string[0] == 0)
6360 return(0);
6361 return(((unsigned int) string[0]) +
6362 (((unsigned int) string[1]) << 8));
6363 case XML_ATTRIBUTE_NODE:
6364 tmp = ((xmlAttrPtr) node)->children;
6365 break;
6366 case XML_ELEMENT_NODE:
6367 tmp = node->children;
6368 break;
6369 default:
6370 return(0);
6371 }
6372 while (tmp != NULL) {
6373 switch (tmp->type) {
6374 case XML_COMMENT_NODE:
6375 case XML_PI_NODE:
6376 case XML_CDATA_SECTION_NODE:
6377 case XML_TEXT_NODE:
6378 string = tmp->content;
6379 break;
6380 case XML_NAMESPACE_DECL:
6381 string = ((xmlNsPtr)tmp)->href;
6382 break;
6383 default:
6384 break;
6385 }
6386 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006387 if (len == 1) {
6388 return(ret + (((unsigned int) string[0]) << 8));
6389 }
6390 if (string[1] == 0) {
6391 len = 1;
6392 ret = (unsigned int) string[0];
6393 } else {
6394 return(((unsigned int) string[0]) +
6395 (((unsigned int) string[1]) << 8));
6396 }
6397 }
6398 /*
6399 * Skip to next node
6400 */
6401 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6402 if (tmp->children->type != XML_ENTITY_DECL) {
6403 tmp = tmp->children;
6404 continue;
6405 }
6406 }
6407 if (tmp == node)
6408 break;
6409
6410 if (tmp->next != NULL) {
6411 tmp = tmp->next;
6412 continue;
6413 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006414
Daniel Veillardf06307e2001-07-03 10:35:50 +00006415 do {
6416 tmp = tmp->parent;
6417 if (tmp == NULL)
6418 break;
6419 if (tmp == node) {
6420 tmp = NULL;
6421 break;
6422 }
6423 if (tmp->next != NULL) {
6424 tmp = tmp->next;
6425 break;
6426 }
6427 } while (tmp != NULL);
6428 }
6429 return(ret);
6430}
6431
6432/**
6433 * xmlXPathStringHash:
6434 * @string: a string
6435 *
6436 * Function computing the beginning of the string value of the node,
6437 * used to speed up comparisons
6438 *
6439 * Returns an int usable as a hash
6440 */
6441static unsigned int
6442xmlXPathStringHash(const xmlChar * string) {
6443 if (string == NULL)
6444 return((unsigned int) 0);
6445 if (string[0] == 0)
6446 return(0);
6447 return(((unsigned int) string[0]) +
6448 (((unsigned int) string[1]) << 8));
6449}
6450
6451/**
Owen Taylor3473f882001-02-23 17:55:21 +00006452 * xmlXPathCompareNodeSetFloat:
6453 * @ctxt: the XPath Parser context
6454 * @inf: less than (1) or greater than (0)
6455 * @strict: is the comparison strict
6456 * @arg: the node set
6457 * @f: the value
6458 *
6459 * Implement the compare operation between a nodeset and a number
6460 * @ns < @val (1, 1, ...
6461 * @ns <= @val (1, 0, ...
6462 * @ns > @val (0, 1, ...
6463 * @ns >= @val (0, 0, ...
6464 *
6465 * If one object to be compared is a node-set and the other is a number,
6466 * then the comparison will be true if and only if there is a node in the
6467 * node-set such that the result of performing the comparison on the number
6468 * to be compared and on the result of converting the string-value of that
6469 * node to a number using the number function is true.
6470 *
6471 * Returns 0 or 1 depending on the results of the test.
6472 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006473static int
Owen Taylor3473f882001-02-23 17:55:21 +00006474xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6475 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6476 int i, ret = 0;
6477 xmlNodeSetPtr ns;
6478 xmlChar *str2;
6479
6480 if ((f == NULL) || (arg == NULL) ||
6481 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006482 xmlXPathReleaseObject(ctxt->context, arg);
6483 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006484 return(0);
6485 }
6486 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006487 if (ns != NULL) {
6488 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006489 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006490 if (str2 != NULL) {
6491 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006492 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006493 xmlFree(str2);
6494 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006495 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006496 ret = xmlXPathCompareValues(ctxt, inf, strict);
6497 if (ret)
6498 break;
6499 }
6500 }
Owen Taylor3473f882001-02-23 17:55:21 +00006501 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006502 xmlXPathReleaseObject(ctxt->context, arg);
6503 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006504 return(ret);
6505}
6506
6507/**
6508 * xmlXPathCompareNodeSetString:
6509 * @ctxt: the XPath Parser context
6510 * @inf: less than (1) or greater than (0)
6511 * @strict: is the comparison strict
6512 * @arg: the node set
6513 * @s: the value
6514 *
6515 * Implement the compare operation between a nodeset and a string
6516 * @ns < @val (1, 1, ...
6517 * @ns <= @val (1, 0, ...
6518 * @ns > @val (0, 1, ...
6519 * @ns >= @val (0, 0, ...
6520 *
6521 * If one object to be compared is a node-set and the other is a string,
6522 * then the comparison will be true if and only if there is a node in
6523 * the node-set such that the result of performing the comparison on the
6524 * string-value of the node and the other string is true.
6525 *
6526 * Returns 0 or 1 depending on the results of the test.
6527 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006528static int
Owen Taylor3473f882001-02-23 17:55:21 +00006529xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6530 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6531 int i, ret = 0;
6532 xmlNodeSetPtr ns;
6533 xmlChar *str2;
6534
6535 if ((s == NULL) || (arg == NULL) ||
6536 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006537 xmlXPathReleaseObject(ctxt->context, arg);
6538 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006539 return(0);
6540 }
6541 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006542 if (ns != NULL) {
6543 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006544 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006545 if (str2 != NULL) {
6546 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006547 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006548 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006549 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006550 ret = xmlXPathCompareValues(ctxt, inf, strict);
6551 if (ret)
6552 break;
6553 }
6554 }
Owen Taylor3473f882001-02-23 17:55:21 +00006555 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006556 xmlXPathReleaseObject(ctxt->context, arg);
6557 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006558 return(ret);
6559}
6560
6561/**
6562 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006563 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006564 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006565 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006566 * @arg2: the second node set object
6567 *
6568 * Implement the compare operation on nodesets:
6569 *
6570 * If both objects to be compared are node-sets, then the comparison
6571 * will be true if and only if there is a node in the first node-set
6572 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006573 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006574 * ....
6575 * When neither object to be compared is a node-set and the operator
6576 * is <=, <, >= or >, then the objects are compared by converting both
6577 * objects to numbers and comparing the numbers according to IEEE 754.
6578 * ....
6579 * The number function converts its argument to a number as follows:
6580 * - a string that consists of optional whitespace followed by an
6581 * optional minus sign followed by a Number followed by whitespace
6582 * is converted to the IEEE 754 number that is nearest (according
6583 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6584 * represented by the string; any other string is converted to NaN
6585 *
6586 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006587 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006588 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006589static int
6590xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006591 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6592 int i, j, init = 0;
6593 double val1;
6594 double *values2;
6595 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006596 xmlNodeSetPtr ns1;
6597 xmlNodeSetPtr ns2;
6598
6599 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006600 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6601 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006602 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006603 }
Owen Taylor3473f882001-02-23 17:55:21 +00006604 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006605 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6606 xmlXPathFreeObject(arg1);
6607 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006608 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006609 }
Owen Taylor3473f882001-02-23 17:55:21 +00006610
6611 ns1 = arg1->nodesetval;
6612 ns2 = arg2->nodesetval;
6613
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006614 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006615 xmlXPathFreeObject(arg1);
6616 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006617 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006618 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006619 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006620 xmlXPathFreeObject(arg1);
6621 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006622 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006623 }
Owen Taylor3473f882001-02-23 17:55:21 +00006624
6625 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6626 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006627 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006628 xmlXPathFreeObject(arg1);
6629 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006630 return(0);
6631 }
6632 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006633 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006634 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006635 continue;
6636 for (j = 0;j < ns2->nodeNr;j++) {
6637 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006638 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006639 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006640 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006641 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006642 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006643 ret = (val1 < values2[j]);
6644 else if (inf && !strict)
6645 ret = (val1 <= values2[j]);
6646 else if (!inf && strict)
6647 ret = (val1 > values2[j]);
6648 else if (!inf && !strict)
6649 ret = (val1 >= values2[j]);
6650 if (ret)
6651 break;
6652 }
6653 if (ret)
6654 break;
6655 init = 1;
6656 }
6657 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006658 xmlXPathFreeObject(arg1);
6659 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006660 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006661}
6662
6663/**
6664 * xmlXPathCompareNodeSetValue:
6665 * @ctxt: the XPath Parser context
6666 * @inf: less than (1) or greater than (0)
6667 * @strict: is the comparison strict
6668 * @arg: the node set
6669 * @val: the value
6670 *
6671 * Implement the compare operation between a nodeset and a value
6672 * @ns < @val (1, 1, ...
6673 * @ns <= @val (1, 0, ...
6674 * @ns > @val (0, 1, ...
6675 * @ns >= @val (0, 0, ...
6676 *
6677 * If one object to be compared is a node-set and the other is a boolean,
6678 * then the comparison will be true if and only if the result of performing
6679 * the comparison on the boolean and on the result of converting
6680 * the node-set to a boolean using the boolean function is true.
6681 *
6682 * Returns 0 or 1 depending on the results of the test.
6683 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006684static int
Owen Taylor3473f882001-02-23 17:55:21 +00006685xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6686 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6687 if ((val == NULL) || (arg == NULL) ||
6688 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6689 return(0);
6690
6691 switch(val->type) {
6692 case XPATH_NUMBER:
6693 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6694 case XPATH_NODESET:
6695 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006696 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006697 case XPATH_STRING:
6698 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6699 case XPATH_BOOLEAN:
6700 valuePush(ctxt, arg);
6701 xmlXPathBooleanFunction(ctxt, 1);
6702 valuePush(ctxt, val);
6703 return(xmlXPathCompareValues(ctxt, inf, strict));
6704 default:
6705 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006706 }
6707 return(0);
6708}
6709
6710/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006711 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006712 * @arg: the nodeset object argument
6713 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006714 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006715 *
6716 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6717 * If one object to be compared is a node-set and the other is a string,
6718 * then the comparison will be true if and only if there is a node in
6719 * the node-set such that the result of performing the comparison on the
6720 * string-value of the node and the other string is true.
6721 *
6722 * Returns 0 or 1 depending on the results of the test.
6723 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006724static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006725xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006726{
Owen Taylor3473f882001-02-23 17:55:21 +00006727 int i;
6728 xmlNodeSetPtr ns;
6729 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006730 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006731
6732 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006733 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6734 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006735 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006736 /*
6737 * A NULL nodeset compared with a string is always false
6738 * (since there is no node equal, and no node not equal)
6739 */
6740 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006741 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006742 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006743 for (i = 0; i < ns->nodeNr; i++) {
6744 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6745 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6746 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6747 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006748 if (neq)
6749 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006750 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006751 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6752 if (neq)
6753 continue;
6754 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006755 } else if (neq) {
6756 if (str2 != NULL)
6757 xmlFree(str2);
6758 return (1);
6759 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006760 if (str2 != NULL)
6761 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006762 } else if (neq)
6763 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006764 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006765 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006766}
6767
6768/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006769 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006770 * @arg: the nodeset object argument
6771 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006772 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006773 *
6774 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6775 * If one object to be compared is a node-set and the other is a number,
6776 * then the comparison will be true if and only if there is a node in
6777 * the node-set such that the result of performing the comparison on the
6778 * number to be compared and on the result of converting the string-value
6779 * of that node to a number using the number function is true.
6780 *
6781 * Returns 0 or 1 depending on the results of the test.
6782 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006783static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006784xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6785 xmlXPathObjectPtr arg, double f, int neq) {
6786 int i, ret=0;
6787 xmlNodeSetPtr ns;
6788 xmlChar *str2;
6789 xmlXPathObjectPtr val;
6790 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006791
6792 if ((arg == NULL) ||
6793 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6794 return(0);
6795
William M. Brack0c022ad2002-07-12 00:56:01 +00006796 ns = arg->nodesetval;
6797 if (ns != NULL) {
6798 for (i=0;i<ns->nodeNr;i++) {
6799 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6800 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006801 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006802 xmlFree(str2);
6803 xmlXPathNumberFunction(ctxt, 1);
6804 val = valuePop(ctxt);
6805 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006806 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006807 if (!xmlXPathIsNaN(v)) {
6808 if ((!neq) && (v==f)) {
6809 ret = 1;
6810 break;
6811 } else if ((neq) && (v!=f)) {
6812 ret = 1;
6813 break;
6814 }
William M. Brack32f0f712005-07-14 07:00:33 +00006815 } else { /* NaN is unequal to any value */
6816 if (neq)
6817 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006818 }
6819 }
6820 }
6821 }
6822
6823 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006824}
6825
6826
6827/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006828 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006829 * @arg1: first nodeset object argument
6830 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006831 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006832 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006833 * Implement the equal / not equal operation on XPath nodesets:
6834 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006835 * If both objects to be compared are node-sets, then the comparison
6836 * will be true if and only if there is a node in the first node-set and
6837 * a node in the second node-set such that the result of performing the
6838 * comparison on the string-values of the two nodes is true.
6839 *
6840 * (needless to say, this is a costly operation)
6841 *
6842 * Returns 0 or 1 depending on the results of the test.
6843 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006844static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006845xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006846 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006847 unsigned int *hashs1;
6848 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006849 xmlChar **values1;
6850 xmlChar **values2;
6851 int ret = 0;
6852 xmlNodeSetPtr ns1;
6853 xmlNodeSetPtr ns2;
6854
6855 if ((arg1 == NULL) ||
6856 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6857 return(0);
6858 if ((arg2 == NULL) ||
6859 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6860 return(0);
6861
6862 ns1 = arg1->nodesetval;
6863 ns2 = arg2->nodesetval;
6864
Daniel Veillard911f49a2001-04-07 15:39:35 +00006865 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006866 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006867 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006868 return(0);
6869
6870 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006871 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006872 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006873 if (neq == 0)
6874 for (i = 0;i < ns1->nodeNr;i++)
6875 for (j = 0;j < ns2->nodeNr;j++)
6876 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6877 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006878
6879 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006880 if (values1 == NULL) {
6881 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006882 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006883 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006884 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6885 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006886 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006887 xmlFree(values1);
6888 return(0);
6889 }
Owen Taylor3473f882001-02-23 17:55:21 +00006890 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6891 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6892 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006893 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006894 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006895 xmlFree(values1);
6896 return(0);
6897 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006898 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6899 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006900 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006901 xmlFree(hashs1);
6902 xmlFree(values1);
6903 xmlFree(values2);
6904 return(0);
6905 }
Owen Taylor3473f882001-02-23 17:55:21 +00006906 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6907 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006908 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006909 for (j = 0;j < ns2->nodeNr;j++) {
6910 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006911 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006912 if (hashs1[i] != hashs2[j]) {
6913 if (neq) {
6914 ret = 1;
6915 break;
6916 }
6917 }
6918 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006919 if (values1[i] == NULL)
6920 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6921 if (values2[j] == NULL)
6922 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006923 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006924 if (ret)
6925 break;
6926 }
Owen Taylor3473f882001-02-23 17:55:21 +00006927 }
6928 if (ret)
6929 break;
6930 }
6931 for (i = 0;i < ns1->nodeNr;i++)
6932 if (values1[i] != NULL)
6933 xmlFree(values1[i]);
6934 for (j = 0;j < ns2->nodeNr;j++)
6935 if (values2[j] != NULL)
6936 xmlFree(values2[j]);
6937 xmlFree(values1);
6938 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006939 xmlFree(hashs1);
6940 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006941 return(ret);
6942}
6943
William M. Brack0c022ad2002-07-12 00:56:01 +00006944static int
6945xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6946 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006947 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006948 /*
6949 *At this point we are assured neither arg1 nor arg2
6950 *is a nodeset, so we can just pick the appropriate routine.
6951 */
Owen Taylor3473f882001-02-23 17:55:21 +00006952 switch (arg1->type) {
6953 case XPATH_UNDEFINED:
6954#ifdef DEBUG_EXPR
6955 xmlGenericError(xmlGenericErrorContext,
6956 "Equal: undefined\n");
6957#endif
6958 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006959 case XPATH_BOOLEAN:
6960 switch (arg2->type) {
6961 case XPATH_UNDEFINED:
6962#ifdef DEBUG_EXPR
6963 xmlGenericError(xmlGenericErrorContext,
6964 "Equal: undefined\n");
6965#endif
6966 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006967 case XPATH_BOOLEAN:
6968#ifdef DEBUG_EXPR
6969 xmlGenericError(xmlGenericErrorContext,
6970 "Equal: %d boolean %d \n",
6971 arg1->boolval, arg2->boolval);
6972#endif
6973 ret = (arg1->boolval == arg2->boolval);
6974 break;
6975 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006976 ret = (arg1->boolval ==
6977 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006978 break;
6979 case XPATH_STRING:
6980 if ((arg2->stringval == NULL) ||
6981 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006982 else
Owen Taylor3473f882001-02-23 17:55:21 +00006983 ret = 1;
6984 ret = (arg1->boolval == ret);
6985 break;
6986 case XPATH_USERS:
6987 case XPATH_POINT:
6988 case XPATH_RANGE:
6989 case XPATH_LOCATIONSET:
6990 TODO
6991 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006992 case XPATH_NODESET:
6993 case XPATH_XSLT_TREE:
6994 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006995 }
6996 break;
6997 case XPATH_NUMBER:
6998 switch (arg2->type) {
6999 case XPATH_UNDEFINED:
7000#ifdef DEBUG_EXPR
7001 xmlGenericError(xmlGenericErrorContext,
7002 "Equal: undefined\n");
7003#endif
7004 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007005 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00007006 ret = (arg2->boolval==
7007 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007008 break;
7009 case XPATH_STRING:
7010 valuePush(ctxt, arg2);
7011 xmlXPathNumberFunction(ctxt, 1);
7012 arg2 = valuePop(ctxt);
7013 /* no break on purpose */
7014 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007015 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007016 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007017 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007018 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007019 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7020 if (xmlXPathIsInf(arg2->floatval) == 1)
7021 ret = 1;
7022 else
7023 ret = 0;
7024 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7025 if (xmlXPathIsInf(arg2->floatval) == -1)
7026 ret = 1;
7027 else
7028 ret = 0;
7029 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7030 if (xmlXPathIsInf(arg1->floatval) == 1)
7031 ret = 1;
7032 else
7033 ret = 0;
7034 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7035 if (xmlXPathIsInf(arg1->floatval) == -1)
7036 ret = 1;
7037 else
7038 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007039 } else {
7040 ret = (arg1->floatval == arg2->floatval);
7041 }
Owen Taylor3473f882001-02-23 17:55:21 +00007042 break;
7043 case XPATH_USERS:
7044 case XPATH_POINT:
7045 case XPATH_RANGE:
7046 case XPATH_LOCATIONSET:
7047 TODO
7048 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007049 case XPATH_NODESET:
7050 case XPATH_XSLT_TREE:
7051 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007052 }
7053 break;
7054 case XPATH_STRING:
7055 switch (arg2->type) {
7056 case XPATH_UNDEFINED:
7057#ifdef DEBUG_EXPR
7058 xmlGenericError(xmlGenericErrorContext,
7059 "Equal: undefined\n");
7060#endif
7061 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007062 case XPATH_BOOLEAN:
7063 if ((arg1->stringval == NULL) ||
7064 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007065 else
Owen Taylor3473f882001-02-23 17:55:21 +00007066 ret = 1;
7067 ret = (arg2->boolval == ret);
7068 break;
7069 case XPATH_STRING:
7070 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7071 break;
7072 case XPATH_NUMBER:
7073 valuePush(ctxt, arg1);
7074 xmlXPathNumberFunction(ctxt, 1);
7075 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007076 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007077 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007078 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007079 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007080 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7081 if (xmlXPathIsInf(arg2->floatval) == 1)
7082 ret = 1;
7083 else
7084 ret = 0;
7085 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7086 if (xmlXPathIsInf(arg2->floatval) == -1)
7087 ret = 1;
7088 else
7089 ret = 0;
7090 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7091 if (xmlXPathIsInf(arg1->floatval) == 1)
7092 ret = 1;
7093 else
7094 ret = 0;
7095 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7096 if (xmlXPathIsInf(arg1->floatval) == -1)
7097 ret = 1;
7098 else
7099 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007100 } else {
7101 ret = (arg1->floatval == arg2->floatval);
7102 }
Owen Taylor3473f882001-02-23 17:55:21 +00007103 break;
7104 case XPATH_USERS:
7105 case XPATH_POINT:
7106 case XPATH_RANGE:
7107 case XPATH_LOCATIONSET:
7108 TODO
7109 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007110 case XPATH_NODESET:
7111 case XPATH_XSLT_TREE:
7112 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007113 }
7114 break;
7115 case XPATH_USERS:
7116 case XPATH_POINT:
7117 case XPATH_RANGE:
7118 case XPATH_LOCATIONSET:
7119 TODO
7120 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007121 case XPATH_NODESET:
7122 case XPATH_XSLT_TREE:
7123 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007124 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007125 xmlXPathReleaseObject(ctxt->context, arg1);
7126 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007127 return(ret);
7128}
7129
William M. Brack0c022ad2002-07-12 00:56:01 +00007130/**
7131 * xmlXPathEqualValues:
7132 * @ctxt: the XPath Parser context
7133 *
7134 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7135 *
7136 * Returns 0 or 1 depending on the results of the test.
7137 */
7138int
7139xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7140 xmlXPathObjectPtr arg1, arg2, argtmp;
7141 int ret = 0;
7142
Daniel Veillard6128c012004-11-08 17:16:15 +00007143 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007144 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007145 arg1 = valuePop(ctxt);
7146 if ((arg1 == NULL) || (arg2 == NULL)) {
7147 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007148 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007149 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007150 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007151 XP_ERROR0(XPATH_INVALID_OPERAND);
7152 }
7153
7154 if (arg1 == arg2) {
7155#ifdef DEBUG_EXPR
7156 xmlGenericError(xmlGenericErrorContext,
7157 "Equal: by pointer\n");
7158#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007159 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007160 return(1);
7161 }
7162
7163 /*
7164 *If either argument is a nodeset, it's a 'special case'
7165 */
7166 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7167 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7168 /*
7169 *Hack it to assure arg1 is the nodeset
7170 */
7171 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7172 argtmp = arg2;
7173 arg2 = arg1;
7174 arg1 = argtmp;
7175 }
7176 switch (arg2->type) {
7177 case XPATH_UNDEFINED:
7178#ifdef DEBUG_EXPR
7179 xmlGenericError(xmlGenericErrorContext,
7180 "Equal: undefined\n");
7181#endif
7182 break;
7183 case XPATH_NODESET:
7184 case XPATH_XSLT_TREE:
7185 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7186 break;
7187 case XPATH_BOOLEAN:
7188 if ((arg1->nodesetval == NULL) ||
7189 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007190 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007191 ret = 1;
7192 ret = (ret == arg2->boolval);
7193 break;
7194 case XPATH_NUMBER:
7195 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7196 break;
7197 case XPATH_STRING:
7198 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7199 break;
7200 case XPATH_USERS:
7201 case XPATH_POINT:
7202 case XPATH_RANGE:
7203 case XPATH_LOCATIONSET:
7204 TODO
7205 break;
7206 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007207 xmlXPathReleaseObject(ctxt->context, arg1);
7208 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007209 return(ret);
7210 }
7211
7212 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7213}
7214
7215/**
7216 * xmlXPathNotEqualValues:
7217 * @ctxt: the XPath Parser context
7218 *
7219 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7220 *
7221 * Returns 0 or 1 depending on the results of the test.
7222 */
7223int
7224xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7225 xmlXPathObjectPtr arg1, arg2, argtmp;
7226 int ret = 0;
7227
Daniel Veillard6128c012004-11-08 17:16:15 +00007228 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007229 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007230 arg1 = valuePop(ctxt);
7231 if ((arg1 == NULL) || (arg2 == NULL)) {
7232 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007233 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007234 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007235 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007236 XP_ERROR0(XPATH_INVALID_OPERAND);
7237 }
7238
7239 if (arg1 == arg2) {
7240#ifdef DEBUG_EXPR
7241 xmlGenericError(xmlGenericErrorContext,
7242 "NotEqual: by pointer\n");
7243#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007244 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007245 return(0);
7246 }
7247
7248 /*
7249 *If either argument is a nodeset, it's a 'special case'
7250 */
7251 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7252 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7253 /*
7254 *Hack it to assure arg1 is the nodeset
7255 */
7256 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7257 argtmp = arg2;
7258 arg2 = arg1;
7259 arg1 = argtmp;
7260 }
7261 switch (arg2->type) {
7262 case XPATH_UNDEFINED:
7263#ifdef DEBUG_EXPR
7264 xmlGenericError(xmlGenericErrorContext,
7265 "NotEqual: undefined\n");
7266#endif
7267 break;
7268 case XPATH_NODESET:
7269 case XPATH_XSLT_TREE:
7270 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7271 break;
7272 case XPATH_BOOLEAN:
7273 if ((arg1->nodesetval == NULL) ||
7274 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007275 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007276 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007277 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007278 break;
7279 case XPATH_NUMBER:
7280 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7281 break;
7282 case XPATH_STRING:
7283 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7284 break;
7285 case XPATH_USERS:
7286 case XPATH_POINT:
7287 case XPATH_RANGE:
7288 case XPATH_LOCATIONSET:
7289 TODO
7290 break;
7291 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007292 xmlXPathReleaseObject(ctxt->context, arg1);
7293 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007294 return(ret);
7295 }
7296
7297 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7298}
Owen Taylor3473f882001-02-23 17:55:21 +00007299
7300/**
7301 * xmlXPathCompareValues:
7302 * @ctxt: the XPath Parser context
7303 * @inf: less than (1) or greater than (0)
7304 * @strict: is the comparison strict
7305 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007306 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007307 * @arg1 < @arg2 (1, 1, ...
7308 * @arg1 <= @arg2 (1, 0, ...
7309 * @arg1 > @arg2 (0, 1, ...
7310 * @arg1 >= @arg2 (0, 0, ...
7311 *
7312 * When neither object to be compared is a node-set and the operator is
7313 * <=, <, >=, >, then the objects are compared by converted both objects
7314 * to numbers and comparing the numbers according to IEEE 754. The <
7315 * comparison will be true if and only if the first number is less than the
7316 * second number. The <= comparison will be true if and only if the first
7317 * number is less than or equal to the second number. The > comparison
7318 * will be true if and only if the first number is greater than the second
7319 * number. The >= comparison will be true if and only if the first number
7320 * is greater than or equal to the second number.
7321 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007322 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007323 */
7324int
7325xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007326 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007327 xmlXPathObjectPtr arg1, arg2;
7328
Daniel Veillard6128c012004-11-08 17:16:15 +00007329 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007330 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007331 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007332 if ((arg1 == NULL) || (arg2 == NULL)) {
7333 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007334 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007335 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007336 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007337 XP_ERROR0(XPATH_INVALID_OPERAND);
7338 }
7339
William M. Brack0c022ad2002-07-12 00:56:01 +00007340 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7341 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007342 /*
7343 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7344 * are not freed from within this routine; they will be freed from the
7345 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7346 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007347 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7348 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007349 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007350 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007351 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007352 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7353 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007354 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007355 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7356 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007357 }
7358 }
7359 return(ret);
7360 }
7361
7362 if (arg1->type != XPATH_NUMBER) {
7363 valuePush(ctxt, arg1);
7364 xmlXPathNumberFunction(ctxt, 1);
7365 arg1 = valuePop(ctxt);
7366 }
7367 if (arg1->type != XPATH_NUMBER) {
7368 xmlXPathFreeObject(arg1);
7369 xmlXPathFreeObject(arg2);
7370 XP_ERROR0(XPATH_INVALID_OPERAND);
7371 }
7372 if (arg2->type != XPATH_NUMBER) {
7373 valuePush(ctxt, arg2);
7374 xmlXPathNumberFunction(ctxt, 1);
7375 arg2 = valuePop(ctxt);
7376 }
7377 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007378 xmlXPathReleaseObject(ctxt->context, arg1);
7379 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007380 XP_ERROR0(XPATH_INVALID_OPERAND);
7381 }
7382 /*
7383 * Add tests for infinity and nan
7384 * => feedback on 3.4 for Inf and NaN
7385 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007386 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007387 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007388 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007389 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007390 arg1i=xmlXPathIsInf(arg1->floatval);
7391 arg2i=xmlXPathIsInf(arg2->floatval);
7392 if (inf && strict) {
7393 if ((arg1i == -1 && arg2i != -1) ||
7394 (arg2i == 1 && arg1i != 1)) {
7395 ret = 1;
7396 } else if (arg1i == 0 && arg2i == 0) {
7397 ret = (arg1->floatval < arg2->floatval);
7398 } else {
7399 ret = 0;
7400 }
7401 }
7402 else if (inf && !strict) {
7403 if (arg1i == -1 || arg2i == 1) {
7404 ret = 1;
7405 } else if (arg1i == 0 && arg2i == 0) {
7406 ret = (arg1->floatval <= arg2->floatval);
7407 } else {
7408 ret = 0;
7409 }
7410 }
7411 else if (!inf && strict) {
7412 if ((arg1i == 1 && arg2i != 1) ||
7413 (arg2i == -1 && arg1i != -1)) {
7414 ret = 1;
7415 } else if (arg1i == 0 && arg2i == 0) {
7416 ret = (arg1->floatval > arg2->floatval);
7417 } else {
7418 ret = 0;
7419 }
7420 }
7421 else if (!inf && !strict) {
7422 if (arg1i == 1 || arg2i == -1) {
7423 ret = 1;
7424 } else if (arg1i == 0 && arg2i == 0) {
7425 ret = (arg1->floatval >= arg2->floatval);
7426 } else {
7427 ret = 0;
7428 }
7429 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007430 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007431 xmlXPathReleaseObject(ctxt->context, arg1);
7432 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007433 return(ret);
7434}
7435
7436/**
7437 * xmlXPathValueFlipSign:
7438 * @ctxt: the XPath Parser context
7439 *
7440 * Implement the unary - operation on an XPath object
7441 * The numeric operators convert their operands to numbers as if
7442 * by calling the number function.
7443 */
7444void
7445xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007446 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007447 CAST_TO_NUMBER;
7448 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007449 if (xmlXPathIsNaN(ctxt->value->floatval))
7450 ctxt->value->floatval=xmlXPathNAN;
7451 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7452 ctxt->value->floatval=xmlXPathNINF;
7453 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7454 ctxt->value->floatval=xmlXPathPINF;
7455 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007456 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7457 ctxt->value->floatval = xmlXPathNZERO;
7458 else
7459 ctxt->value->floatval = 0;
7460 }
7461 else
7462 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007463}
7464
7465/**
7466 * xmlXPathAddValues:
7467 * @ctxt: the XPath Parser context
7468 *
7469 * Implement the add operation on XPath objects:
7470 * The numeric operators convert their operands to numbers as if
7471 * by calling the number function.
7472 */
7473void
7474xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7475 xmlXPathObjectPtr arg;
7476 double val;
7477
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007478 arg = valuePop(ctxt);
7479 if (arg == NULL)
7480 XP_ERROR(XPATH_INVALID_OPERAND);
7481 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007482 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007483 CAST_TO_NUMBER;
7484 CHECK_TYPE(XPATH_NUMBER);
7485 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007486}
7487
7488/**
7489 * xmlXPathSubValues:
7490 * @ctxt: the XPath Parser context
7491 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007492 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007493 * The numeric operators convert their operands to numbers as if
7494 * by calling the number function.
7495 */
7496void
7497xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7498 xmlXPathObjectPtr arg;
7499 double val;
7500
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007501 arg = valuePop(ctxt);
7502 if (arg == NULL)
7503 XP_ERROR(XPATH_INVALID_OPERAND);
7504 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007505 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007506 CAST_TO_NUMBER;
7507 CHECK_TYPE(XPATH_NUMBER);
7508 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007509}
7510
7511/**
7512 * xmlXPathMultValues:
7513 * @ctxt: the XPath Parser context
7514 *
7515 * Implement the multiply operation on XPath objects:
7516 * The numeric operators convert their operands to numbers as if
7517 * by calling the number function.
7518 */
7519void
7520xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7521 xmlXPathObjectPtr arg;
7522 double val;
7523
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007524 arg = valuePop(ctxt);
7525 if (arg == NULL)
7526 XP_ERROR(XPATH_INVALID_OPERAND);
7527 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007528 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007529 CAST_TO_NUMBER;
7530 CHECK_TYPE(XPATH_NUMBER);
7531 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007532}
7533
7534/**
7535 * xmlXPathDivValues:
7536 * @ctxt: the XPath Parser context
7537 *
7538 * Implement the div operation on XPath objects @arg1 / @arg2:
7539 * The numeric operators convert their operands to numbers as if
7540 * by calling the number function.
7541 */
7542void
7543xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7544 xmlXPathObjectPtr arg;
7545 double val;
7546
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007547 arg = valuePop(ctxt);
7548 if (arg == NULL)
7549 XP_ERROR(XPATH_INVALID_OPERAND);
7550 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007551 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007552 CAST_TO_NUMBER;
7553 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007554 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7555 ctxt->value->floatval = xmlXPathNAN;
7556 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007557 if (ctxt->value->floatval == 0)
7558 ctxt->value->floatval = xmlXPathNAN;
7559 else if (ctxt->value->floatval > 0)
7560 ctxt->value->floatval = xmlXPathNINF;
7561 else if (ctxt->value->floatval < 0)
7562 ctxt->value->floatval = xmlXPathPINF;
7563 }
7564 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007565 if (ctxt->value->floatval == 0)
7566 ctxt->value->floatval = xmlXPathNAN;
7567 else if (ctxt->value->floatval > 0)
7568 ctxt->value->floatval = xmlXPathPINF;
7569 else if (ctxt->value->floatval < 0)
7570 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007571 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007572 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007573}
7574
7575/**
7576 * xmlXPathModValues:
7577 * @ctxt: the XPath Parser context
7578 *
7579 * Implement the mod operation on XPath objects: @arg1 / @arg2
7580 * The numeric operators convert their operands to numbers as if
7581 * by calling the number function.
7582 */
7583void
7584xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7585 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007586 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007587
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007588 arg = valuePop(ctxt);
7589 if (arg == NULL)
7590 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007591 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007592 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007593 CAST_TO_NUMBER;
7594 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007595 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007596 if (arg2 == 0)
7597 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007598 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007599 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007600 }
Owen Taylor3473f882001-02-23 17:55:21 +00007601}
7602
7603/************************************************************************
7604 * *
7605 * The traversal functions *
7606 * *
7607 ************************************************************************/
7608
Owen Taylor3473f882001-02-23 17:55:21 +00007609/*
7610 * A traversal function enumerates nodes along an axis.
7611 * Initially it must be called with NULL, and it indicates
7612 * termination on the axis by returning NULL.
7613 */
7614typedef xmlNodePtr (*xmlXPathTraversalFunction)
7615 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7616
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007617/*
7618 * xmlXPathTraversalFunctionExt:
7619 * A traversal function enumerates nodes along an axis.
7620 * Initially it must be called with NULL, and it indicates
7621 * termination on the axis by returning NULL.
7622 * The context node of the traversal is specified via @contextNode.
7623 */
7624typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7625 (xmlNodePtr cur, xmlNodePtr contextNode);
7626
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007627/*
7628 * xmlXPathNodeSetMergeFunction:
7629 * Used for merging node sets in xmlXPathCollectAndTest().
7630 */
7631typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7632 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7633
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007634
Owen Taylor3473f882001-02-23 17:55:21 +00007635/**
7636 * xmlXPathNextSelf:
7637 * @ctxt: the XPath Parser context
7638 * @cur: the current node in the traversal
7639 *
7640 * Traversal function for the "self" direction
7641 * The self axis contains just the context node itself
7642 *
7643 * Returns the next element following that axis
7644 */
7645xmlNodePtr
7646xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007647 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007648 if (cur == NULL)
7649 return(ctxt->context->node);
7650 return(NULL);
7651}
7652
7653/**
7654 * xmlXPathNextChild:
7655 * @ctxt: the XPath Parser context
7656 * @cur: the current node in the traversal
7657 *
7658 * Traversal function for the "child" direction
7659 * The child axis contains the children of the context node in document order.
7660 *
7661 * Returns the next element following that axis
7662 */
7663xmlNodePtr
7664xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007665 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007666 if (cur == NULL) {
7667 if (ctxt->context->node == NULL) return(NULL);
7668 switch (ctxt->context->node->type) {
7669 case XML_ELEMENT_NODE:
7670 case XML_TEXT_NODE:
7671 case XML_CDATA_SECTION_NODE:
7672 case XML_ENTITY_REF_NODE:
7673 case XML_ENTITY_NODE:
7674 case XML_PI_NODE:
7675 case XML_COMMENT_NODE:
7676 case XML_NOTATION_NODE:
7677 case XML_DTD_NODE:
7678 return(ctxt->context->node->children);
7679 case XML_DOCUMENT_NODE:
7680 case XML_DOCUMENT_TYPE_NODE:
7681 case XML_DOCUMENT_FRAG_NODE:
7682 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007683#ifdef LIBXML_DOCB_ENABLED
7684 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007685#endif
7686 return(((xmlDocPtr) ctxt->context->node)->children);
7687 case XML_ELEMENT_DECL:
7688 case XML_ATTRIBUTE_DECL:
7689 case XML_ENTITY_DECL:
7690 case XML_ATTRIBUTE_NODE:
7691 case XML_NAMESPACE_DECL:
7692 case XML_XINCLUDE_START:
7693 case XML_XINCLUDE_END:
7694 return(NULL);
7695 }
7696 return(NULL);
7697 }
7698 if ((cur->type == XML_DOCUMENT_NODE) ||
7699 (cur->type == XML_HTML_DOCUMENT_NODE))
7700 return(NULL);
7701 return(cur->next);
7702}
7703
7704/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007705 * xmlXPathNextChildElement:
7706 * @ctxt: the XPath Parser context
7707 * @cur: the current node in the traversal
7708 *
7709 * Traversal function for the "child" direction and nodes of type element.
7710 * The child axis contains the children of the context node in document order.
7711 *
7712 * Returns the next element following that axis
7713 */
7714static xmlNodePtr
7715xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7716 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7717 if (cur == NULL) {
7718 cur = ctxt->context->node;
7719 if (cur == NULL) return(NULL);
7720 /*
7721 * Get the first element child.
7722 */
7723 switch (cur->type) {
7724 case XML_ELEMENT_NODE:
7725 case XML_DOCUMENT_FRAG_NODE:
7726 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7727 case XML_ENTITY_NODE:
7728 cur = cur->children;
7729 if (cur != NULL) {
7730 if (cur->type == XML_ELEMENT_NODE)
7731 return(cur);
7732 do {
7733 cur = cur->next;
7734 } while ((cur != NULL) &&
7735 (cur->type != XML_ELEMENT_NODE));
7736 return(cur);
7737 }
7738 return(NULL);
7739 case XML_DOCUMENT_NODE:
7740 case XML_HTML_DOCUMENT_NODE:
7741#ifdef LIBXML_DOCB_ENABLED
7742 case XML_DOCB_DOCUMENT_NODE:
7743#endif
7744 return(xmlDocGetRootElement((xmlDocPtr) cur));
7745 default:
7746 return(NULL);
7747 }
7748 return(NULL);
7749 }
7750 /*
7751 * Get the next sibling element node.
7752 */
7753 switch (cur->type) {
7754 case XML_ELEMENT_NODE:
7755 case XML_TEXT_NODE:
7756 case XML_ENTITY_REF_NODE:
7757 case XML_ENTITY_NODE:
7758 case XML_CDATA_SECTION_NODE:
7759 case XML_PI_NODE:
7760 case XML_COMMENT_NODE:
7761 case XML_XINCLUDE_END:
7762 break;
7763 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7764 default:
7765 return(NULL);
7766 }
7767 if (cur->next != NULL) {
7768 if (cur->next->type == XML_ELEMENT_NODE)
7769 return(cur->next);
7770 cur = cur->next;
7771 do {
7772 cur = cur->next;
7773 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7774 return(cur);
7775 }
7776 return(NULL);
7777}
7778
Daniel Veillard76516062012-09-11 14:02:08 +08007779#if 0
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007780/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007781 * xmlXPathNextDescendantOrSelfElemParent:
7782 * @ctxt: the XPath Parser context
7783 * @cur: the current node in the traversal
7784 *
7785 * Traversal function for the "descendant-or-self" axis.
7786 * Additionally it returns only nodes which can be parents of
7787 * element nodes.
7788 *
7789 *
7790 * Returns the next element following that axis
7791 */
7792static xmlNodePtr
7793xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7794 xmlNodePtr contextNode)
7795{
7796 if (cur == NULL) {
7797 if (contextNode == NULL)
7798 return(NULL);
7799 switch (contextNode->type) {
7800 case XML_ELEMENT_NODE:
7801 case XML_XINCLUDE_START:
7802 case XML_DOCUMENT_FRAG_NODE:
7803 case XML_DOCUMENT_NODE:
7804#ifdef LIBXML_DOCB_ENABLED
7805 case XML_DOCB_DOCUMENT_NODE:
7806#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007807 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007808 return(contextNode);
7809 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007810 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007811 }
7812 return(NULL);
7813 } else {
7814 xmlNodePtr start = cur;
7815
7816 while (cur != NULL) {
7817 switch (cur->type) {
7818 case XML_ELEMENT_NODE:
7819 /* TODO: OK to have XInclude here? */
7820 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007821 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007822 if (cur != start)
7823 return(cur);
7824 if (cur->children != NULL) {
7825 cur = cur->children;
7826 continue;
7827 }
7828 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007829 /* Not sure if we need those here. */
7830 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007831#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007832 case XML_DOCB_DOCUMENT_NODE:
7833#endif
7834 case XML_HTML_DOCUMENT_NODE:
7835 if (cur != start)
7836 return(cur);
7837 return(xmlDocGetRootElement((xmlDocPtr) cur));
7838 default:
7839 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007840 }
7841
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007842next_sibling:
7843 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007844 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007845 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007846 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007847 } else {
7848 cur = cur->parent;
7849 goto next_sibling;
7850 }
7851 }
7852 }
7853 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007854}
Daniel Veillard76516062012-09-11 14:02:08 +08007855#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007856
7857/**
Owen Taylor3473f882001-02-23 17:55:21 +00007858 * xmlXPathNextDescendant:
7859 * @ctxt: the XPath Parser context
7860 * @cur: the current node in the traversal
7861 *
7862 * Traversal function for the "descendant" direction
7863 * the descendant axis contains the descendants of the context node in document
7864 * order; a descendant is a child or a child of a child and so on.
7865 *
7866 * Returns the next element following that axis
7867 */
7868xmlNodePtr
7869xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007870 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007871 if (cur == NULL) {
7872 if (ctxt->context->node == NULL)
7873 return(NULL);
7874 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7875 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7876 return(NULL);
7877
7878 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7879 return(ctxt->context->doc->children);
7880 return(ctxt->context->node->children);
7881 }
7882
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007883 if (cur->type == XML_NAMESPACE_DECL)
7884 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007885 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007886 /*
7887 * Do not descend on entities declarations
7888 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007889 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007890 cur = cur->children;
7891 /*
7892 * Skip DTDs
7893 */
7894 if (cur->type != XML_DTD_NODE)
7895 return(cur);
7896 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007897 }
7898
7899 if (cur == ctxt->context->node) return(NULL);
7900
Daniel Veillard68e9e742002-11-16 15:35:11 +00007901 while (cur->next != NULL) {
7902 cur = cur->next;
7903 if ((cur->type != XML_ENTITY_DECL) &&
7904 (cur->type != XML_DTD_NODE))
7905 return(cur);
7906 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007907
Owen Taylor3473f882001-02-23 17:55:21 +00007908 do {
7909 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007910 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007911 if (cur == ctxt->context->node) return(NULL);
7912 if (cur->next != NULL) {
7913 cur = cur->next;
7914 return(cur);
7915 }
7916 } while (cur != NULL);
7917 return(cur);
7918}
7919
7920/**
7921 * xmlXPathNextDescendantOrSelf:
7922 * @ctxt: the XPath Parser context
7923 * @cur: the current node in the traversal
7924 *
7925 * Traversal function for the "descendant-or-self" direction
7926 * the descendant-or-self axis contains the context node and the descendants
7927 * of the context node in document order; thus the context node is the first
7928 * node on the axis, and the first child of the context node is the second node
7929 * on the axis
7930 *
7931 * Returns the next element following that axis
7932 */
7933xmlNodePtr
7934xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007935 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Xin Li28c53d32017-03-07 00:33:02 +00007936 if (cur == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00007937 return(ctxt->context->node);
Xin Li28c53d32017-03-07 00:33:02 +00007938
7939 if (ctxt->context->node == NULL)
7940 return(NULL);
7941 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7942 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7943 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007944
7945 return(xmlXPathNextDescendant(ctxt, cur));
7946}
7947
7948/**
7949 * xmlXPathNextParent:
7950 * @ctxt: the XPath Parser context
7951 * @cur: the current node in the traversal
7952 *
7953 * Traversal function for the "parent" direction
7954 * The parent axis contains the parent of the context node, if there is one.
7955 *
7956 * Returns the next element following that axis
7957 */
7958xmlNodePtr
7959xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007960 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007961 /*
7962 * the parent of an attribute or namespace node is the element
7963 * to which the attribute or namespace node is attached
7964 * Namespace handling !!!
7965 */
7966 if (cur == NULL) {
7967 if (ctxt->context->node == NULL) return(NULL);
7968 switch (ctxt->context->node->type) {
7969 case XML_ELEMENT_NODE:
7970 case XML_TEXT_NODE:
7971 case XML_CDATA_SECTION_NODE:
7972 case XML_ENTITY_REF_NODE:
7973 case XML_ENTITY_NODE:
7974 case XML_PI_NODE:
7975 case XML_COMMENT_NODE:
7976 case XML_NOTATION_NODE:
7977 case XML_DTD_NODE:
7978 case XML_ELEMENT_DECL:
7979 case XML_ATTRIBUTE_DECL:
7980 case XML_XINCLUDE_START:
7981 case XML_XINCLUDE_END:
7982 case XML_ENTITY_DECL:
7983 if (ctxt->context->node->parent == NULL)
7984 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007985 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007986 ((ctxt->context->node->parent->name[0] == ' ') ||
7987 (xmlStrEqual(ctxt->context->node->parent->name,
7988 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007989 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007990 return(ctxt->context->node->parent);
7991 case XML_ATTRIBUTE_NODE: {
7992 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7993
7994 return(att->parent);
7995 }
7996 case XML_DOCUMENT_NODE:
7997 case XML_DOCUMENT_TYPE_NODE:
7998 case XML_DOCUMENT_FRAG_NODE:
7999 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008000#ifdef LIBXML_DOCB_ENABLED
8001 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008002#endif
8003 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008004 case XML_NAMESPACE_DECL: {
8005 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008006
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008007 if ((ns->next != NULL) &&
8008 (ns->next->type != XML_NAMESPACE_DECL))
8009 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00008010 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008011 }
Owen Taylor3473f882001-02-23 17:55:21 +00008012 }
8013 }
8014 return(NULL);
8015}
8016
8017/**
8018 * xmlXPathNextAncestor:
8019 * @ctxt: the XPath Parser context
8020 * @cur: the current node in the traversal
8021 *
8022 * Traversal function for the "ancestor" direction
8023 * the ancestor axis contains the ancestors of the context node; the ancestors
8024 * of the context node consist of the parent of context node and the parent's
8025 * parent and so on; the nodes are ordered in reverse document order; thus the
8026 * parent is the first node on the axis, and the parent's parent is the second
8027 * node on the axis
8028 *
8029 * Returns the next element following that axis
8030 */
8031xmlNodePtr
8032xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008033 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008034 /*
8035 * the parent of an attribute or namespace node is the element
8036 * to which the attribute or namespace node is attached
8037 * !!!!!!!!!!!!!
8038 */
8039 if (cur == NULL) {
8040 if (ctxt->context->node == NULL) return(NULL);
8041 switch (ctxt->context->node->type) {
8042 case XML_ELEMENT_NODE:
8043 case XML_TEXT_NODE:
8044 case XML_CDATA_SECTION_NODE:
8045 case XML_ENTITY_REF_NODE:
8046 case XML_ENTITY_NODE:
8047 case XML_PI_NODE:
8048 case XML_COMMENT_NODE:
8049 case XML_DTD_NODE:
8050 case XML_ELEMENT_DECL:
8051 case XML_ATTRIBUTE_DECL:
8052 case XML_ENTITY_DECL:
8053 case XML_NOTATION_NODE:
8054 case XML_XINCLUDE_START:
8055 case XML_XINCLUDE_END:
8056 if (ctxt->context->node->parent == NULL)
8057 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008058 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008059 ((ctxt->context->node->parent->name[0] == ' ') ||
8060 (xmlStrEqual(ctxt->context->node->parent->name,
8061 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008062 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008063 return(ctxt->context->node->parent);
8064 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008065 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00008066
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008067 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00008068 }
8069 case XML_DOCUMENT_NODE:
8070 case XML_DOCUMENT_TYPE_NODE:
8071 case XML_DOCUMENT_FRAG_NODE:
8072 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008073#ifdef LIBXML_DOCB_ENABLED
8074 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008075#endif
8076 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008077 case XML_NAMESPACE_DECL: {
8078 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008079
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008080 if ((ns->next != NULL) &&
8081 (ns->next->type != XML_NAMESPACE_DECL))
8082 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008083 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008084 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008085 }
Owen Taylor3473f882001-02-23 17:55:21 +00008086 }
8087 return(NULL);
8088 }
8089 if (cur == ctxt->context->doc->children)
8090 return((xmlNodePtr) ctxt->context->doc);
8091 if (cur == (xmlNodePtr) ctxt->context->doc)
8092 return(NULL);
8093 switch (cur->type) {
8094 case XML_ELEMENT_NODE:
8095 case XML_TEXT_NODE:
8096 case XML_CDATA_SECTION_NODE:
8097 case XML_ENTITY_REF_NODE:
8098 case XML_ENTITY_NODE:
8099 case XML_PI_NODE:
8100 case XML_COMMENT_NODE:
8101 case XML_NOTATION_NODE:
8102 case XML_DTD_NODE:
8103 case XML_ELEMENT_DECL:
8104 case XML_ATTRIBUTE_DECL:
8105 case XML_ENTITY_DECL:
8106 case XML_XINCLUDE_START:
8107 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008108 if (cur->parent == NULL)
8109 return(NULL);
8110 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008111 ((cur->parent->name[0] == ' ') ||
8112 (xmlStrEqual(cur->parent->name,
8113 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008114 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008115 return(cur->parent);
8116 case XML_ATTRIBUTE_NODE: {
8117 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8118
8119 return(att->parent);
8120 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008121 case XML_NAMESPACE_DECL: {
8122 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008123
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008124 if ((ns->next != NULL) &&
8125 (ns->next->type != XML_NAMESPACE_DECL))
8126 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008127 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008128 return(NULL);
8129 }
Owen Taylor3473f882001-02-23 17:55:21 +00008130 case XML_DOCUMENT_NODE:
8131 case XML_DOCUMENT_TYPE_NODE:
8132 case XML_DOCUMENT_FRAG_NODE:
8133 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008134#ifdef LIBXML_DOCB_ENABLED
8135 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008136#endif
8137 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008138 }
8139 return(NULL);
8140}
8141
8142/**
8143 * xmlXPathNextAncestorOrSelf:
8144 * @ctxt: the XPath Parser context
8145 * @cur: the current node in the traversal
8146 *
8147 * Traversal function for the "ancestor-or-self" direction
8148 * he ancestor-or-self axis contains the context node and ancestors of
8149 * the context node in reverse document order; thus the context node is
8150 * the first node on the axis, and the context node's parent the second;
8151 * parent here is defined the same as with the parent axis.
8152 *
8153 * Returns the next element following that axis
8154 */
8155xmlNodePtr
8156xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008157 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008158 if (cur == NULL)
8159 return(ctxt->context->node);
8160 return(xmlXPathNextAncestor(ctxt, cur));
8161}
8162
8163/**
8164 * xmlXPathNextFollowingSibling:
8165 * @ctxt: the XPath Parser context
8166 * @cur: the current node in the traversal
8167 *
8168 * Traversal function for the "following-sibling" direction
8169 * The following-sibling axis contains the following siblings of the context
8170 * node in document order.
8171 *
8172 * Returns the next element following that axis
8173 */
8174xmlNodePtr
8175xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008176 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008177 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8178 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8179 return(NULL);
8180 if (cur == (xmlNodePtr) ctxt->context->doc)
8181 return(NULL);
8182 if (cur == NULL)
8183 return(ctxt->context->node->next);
8184 return(cur->next);
8185}
8186
8187/**
8188 * xmlXPathNextPrecedingSibling:
8189 * @ctxt: the XPath Parser context
8190 * @cur: the current node in the traversal
8191 *
8192 * Traversal function for the "preceding-sibling" direction
8193 * The preceding-sibling axis contains the preceding siblings of the context
8194 * node in reverse document order; the first preceding sibling is first on the
8195 * axis; the sibling preceding that node is the second on the axis and so on.
8196 *
8197 * Returns the next element following that axis
8198 */
8199xmlNodePtr
8200xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008201 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008202 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8203 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8204 return(NULL);
8205 if (cur == (xmlNodePtr) ctxt->context->doc)
8206 return(NULL);
8207 if (cur == NULL)
8208 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008209 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8210 cur = cur->prev;
8211 if (cur == NULL)
8212 return(ctxt->context->node->prev);
8213 }
Owen Taylor3473f882001-02-23 17:55:21 +00008214 return(cur->prev);
8215}
8216
8217/**
8218 * xmlXPathNextFollowing:
8219 * @ctxt: the XPath Parser context
8220 * @cur: the current node in the traversal
8221 *
8222 * Traversal function for the "following" direction
8223 * The following axis contains all nodes in the same document as the context
8224 * node that are after the context node in document order, excluding any
8225 * descendants and excluding attribute nodes and namespace nodes; the nodes
8226 * are ordered in document order
8227 *
8228 * Returns the next element following that axis
8229 */
8230xmlNodePtr
8231xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008232 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008233 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8234 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8235 return(cur->children);
8236
8237 if (cur == NULL) {
8238 cur = ctxt->context->node;
8239 if (cur->type == XML_NAMESPACE_DECL)
Daniel Veillard91d19752010-10-15 14:30:52 +02008240 return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008241 if (cur->type == XML_ATTRIBUTE_NODE)
8242 cur = cur->parent;
Daniel Veillard91d19752010-10-15 14:30:52 +02008243 }
Owen Taylor3473f882001-02-23 17:55:21 +00008244 if (cur == NULL) return(NULL) ; /* ERROR */
8245 if (cur->next != NULL) return(cur->next) ;
8246 do {
8247 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008248 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008249 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8250 if (cur->next != NULL) return(cur->next);
8251 } while (cur != NULL);
8252 return(cur);
8253}
8254
8255/*
8256 * xmlXPathIsAncestor:
8257 * @ancestor: the ancestor node
8258 * @node: the current node
8259 *
8260 * Check that @ancestor is a @node's ancestor
8261 *
8262 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8263 */
8264static int
8265xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8266 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008267 if (node->type == XML_NAMESPACE_DECL)
8268 return(0);
8269 if (ancestor->type == XML_NAMESPACE_DECL)
8270 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008271 /* nodes need to be in the same document */
8272 if (ancestor->doc != node->doc) return(0);
8273 /* avoid searching if ancestor or node is the root node */
8274 if (ancestor == (xmlNodePtr) node->doc) return(1);
8275 if (node == (xmlNodePtr) ancestor->doc) return(0);
8276 while (node->parent != NULL) {
8277 if (node->parent == ancestor)
8278 return(1);
8279 node = node->parent;
8280 }
8281 return(0);
8282}
8283
8284/**
8285 * xmlXPathNextPreceding:
8286 * @ctxt: the XPath Parser context
8287 * @cur: the current node in the traversal
8288 *
8289 * Traversal function for the "preceding" direction
8290 * the preceding axis contains all nodes in the same document as the context
8291 * node that are before the context node in document order, excluding any
8292 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8293 * ordered in reverse document order
8294 *
8295 * Returns the next element following that axis
8296 */
8297xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008298xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8299{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008300 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008301 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008302 cur = ctxt->context->node;
Daniel Veillardea90b892010-10-22 15:50:50 +02008303 if (cur->type == XML_NAMESPACE_DECL)
8304 return(NULL);
8305 if (cur->type == XML_ATTRIBUTE_NODE)
8306 return(cur->parent);
8307 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008308 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008309 return (NULL);
8310 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8311 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008312 do {
8313 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008314 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8315 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008316 }
8317
8318 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008319 if (cur == NULL)
8320 return (NULL);
8321 if (cur == ctxt->context->doc->children)
8322 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008323 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008324 return (cur);
8325}
8326
8327/**
8328 * xmlXPathNextPrecedingInternal:
8329 * @ctxt: the XPath Parser context
8330 * @cur: the current node in the traversal
8331 *
8332 * Traversal function for the "preceding" direction
8333 * the preceding axis contains all nodes in the same document as the context
8334 * node that are before the context node in document order, excluding any
8335 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8336 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008337 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008338 * state kept in the parser context: ctxt->ancestor.
8339 *
8340 * Returns the next element following that axis
8341 */
8342static xmlNodePtr
8343xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8344 xmlNodePtr cur)
8345{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008346 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008347 if (cur == NULL) {
8348 cur = ctxt->context->node;
8349 if (cur == NULL)
8350 return (NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008351 if (cur->type == XML_NAMESPACE_DECL)
8352 return (NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008353 ctxt->ancestor = cur->parent;
8354 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008355 if (cur->type == XML_NAMESPACE_DECL)
8356 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008357 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8358 cur = cur->prev;
8359 while (cur->prev == NULL) {
8360 cur = cur->parent;
8361 if (cur == NULL)
8362 return (NULL);
8363 if (cur == ctxt->context->doc->children)
8364 return (NULL);
8365 if (cur != ctxt->ancestor)
8366 return (cur);
8367 ctxt->ancestor = cur->parent;
8368 }
8369 cur = cur->prev;
8370 while (cur->last != NULL)
8371 cur = cur->last;
8372 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008373}
8374
8375/**
8376 * xmlXPathNextNamespace:
8377 * @ctxt: the XPath Parser context
8378 * @cur: the current attribute in the traversal
8379 *
8380 * Traversal function for the "namespace" direction
8381 * the namespace axis contains the namespace nodes of the context node;
8382 * the order of nodes on this axis is implementation-defined; the axis will
8383 * be empty unless the context node is an element
8384 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008385 * We keep the XML namespace node at the end of the list.
8386 *
Owen Taylor3473f882001-02-23 17:55:21 +00008387 * Returns the next element following that axis
8388 */
8389xmlNodePtr
8390xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008391 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008392 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Xin Li28c53d32017-03-07 00:33:02 +00008393 if (cur == NULL) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008394 if (ctxt->context->tmpNsList != NULL)
8395 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008396 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008397 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008398 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008399 if (ctxt->context->tmpNsList != NULL) {
8400 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8401 ctxt->context->tmpNsNr++;
8402 }
8403 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008404 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008405 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008406 if (ctxt->context->tmpNsNr > 0) {
8407 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8408 } else {
8409 if (ctxt->context->tmpNsList != NULL)
8410 xmlFree(ctxt->context->tmpNsList);
8411 ctxt->context->tmpNsList = NULL;
8412 return(NULL);
8413 }
Owen Taylor3473f882001-02-23 17:55:21 +00008414}
8415
8416/**
8417 * xmlXPathNextAttribute:
8418 * @ctxt: the XPath Parser context
8419 * @cur: the current attribute in the traversal
8420 *
8421 * Traversal function for the "attribute" direction
8422 * TODO: support DTD inherited default attributes
8423 *
8424 * Returns the next element following that axis
8425 */
8426xmlNodePtr
8427xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008428 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008429 if (ctxt->context->node == NULL)
8430 return(NULL);
8431 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8432 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008433 if (cur == NULL) {
8434 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8435 return(NULL);
8436 return((xmlNodePtr)ctxt->context->node->properties);
8437 }
8438 return((xmlNodePtr)cur->next);
8439}
8440
8441/************************************************************************
8442 * *
8443 * NodeTest Functions *
8444 * *
8445 ************************************************************************/
8446
Owen Taylor3473f882001-02-23 17:55:21 +00008447#define IS_FUNCTION 200
8448
Owen Taylor3473f882001-02-23 17:55:21 +00008449
8450/************************************************************************
8451 * *
8452 * Implicit tree core function library *
8453 * *
8454 ************************************************************************/
8455
8456/**
8457 * xmlXPathRoot:
8458 * @ctxt: the XPath Parser context
8459 *
8460 * Initialize the context to the root of the document
8461 */
8462void
8463xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008464 if ((ctxt == NULL) || (ctxt->context == NULL))
8465 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008466 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008467 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8468 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008469}
8470
8471/************************************************************************
8472 * *
8473 * The explicit core function library *
8474 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8475 * *
8476 ************************************************************************/
8477
8478
8479/**
8480 * xmlXPathLastFunction:
8481 * @ctxt: the XPath Parser context
8482 * @nargs: the number of arguments
8483 *
8484 * Implement the last() XPath function
8485 * number last()
8486 * The last function returns the number of nodes in the context node list.
8487 */
8488void
8489xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8490 CHECK_ARITY(0);
8491 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008492 valuePush(ctxt,
8493 xmlXPathCacheNewFloat(ctxt->context,
8494 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008495#ifdef DEBUG_EXPR
8496 xmlGenericError(xmlGenericErrorContext,
8497 "last() : %d\n", ctxt->context->contextSize);
8498#endif
8499 } else {
8500 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8501 }
8502}
8503
8504/**
8505 * xmlXPathPositionFunction:
8506 * @ctxt: the XPath Parser context
8507 * @nargs: the number of arguments
8508 *
8509 * Implement the position() XPath function
8510 * number position()
8511 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008512 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008513 * will be equal to last().
8514 */
8515void
8516xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8517 CHECK_ARITY(0);
8518 if (ctxt->context->proximityPosition >= 0) {
8519 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008520 xmlXPathCacheNewFloat(ctxt->context,
8521 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008522#ifdef DEBUG_EXPR
8523 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8524 ctxt->context->proximityPosition);
8525#endif
8526 } else {
8527 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8528 }
8529}
8530
8531/**
8532 * xmlXPathCountFunction:
8533 * @ctxt: the XPath Parser context
8534 * @nargs: the number of arguments
8535 *
8536 * Implement the count() XPath function
8537 * number count(node-set)
8538 */
8539void
8540xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8541 xmlXPathObjectPtr cur;
8542
8543 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008544 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008545 ((ctxt->value->type != XPATH_NODESET) &&
8546 (ctxt->value->type != XPATH_XSLT_TREE)))
8547 XP_ERROR(XPATH_INVALID_TYPE);
8548 cur = valuePop(ctxt);
8549
Daniel Veillard911f49a2001-04-07 15:39:35 +00008550 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008551 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008552 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008553 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8554 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008555 } else {
8556 if ((cur->nodesetval->nodeNr != 1) ||
8557 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008558 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008559 } else {
8560 xmlNodePtr tmp;
8561 int i = 0;
8562
8563 tmp = cur->nodesetval->nodeTab[0];
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008564 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
Daniel Veillardfe703322001-08-14 12:18:09 +00008565 tmp = tmp->children;
8566 while (tmp != NULL) {
8567 tmp = tmp->next;
8568 i++;
8569 }
8570 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008571 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008572 }
8573 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008574 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008575}
8576
8577/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008578 * xmlXPathGetElementsByIds:
8579 * @doc: the document
8580 * @ids: a whitespace separated list of IDs
8581 *
8582 * Selects elements by their unique ID.
8583 *
8584 * Returns a node-set of selected elements.
8585 */
8586static xmlNodeSetPtr
8587xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8588 xmlNodeSetPtr ret;
8589 const xmlChar *cur = ids;
8590 xmlChar *ID;
8591 xmlAttrPtr attr;
8592 xmlNodePtr elem = NULL;
8593
Daniel Veillard7a985a12003-07-06 17:57:42 +00008594 if (ids == NULL) return(NULL);
8595
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008596 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008597 if (ret == NULL)
8598 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008599
William M. Brack76e95df2003-10-18 16:20:14 +00008600 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008601 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008602 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008603 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008604
8605 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008606 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008607 /*
8608 * We used to check the fact that the value passed
8609 * was an NCName, but this generated much troubles for
8610 * me and Aleksey Sanin, people blatantly violated that
8611 * constaint, like Visa3D spec.
8612 * if (xmlValidateNCName(ID, 1) == 0)
8613 */
8614 attr = xmlGetID(doc, ID);
8615 if (attr != NULL) {
8616 if (attr->type == XML_ATTRIBUTE_NODE)
8617 elem = attr->parent;
8618 else if (attr->type == XML_ELEMENT_NODE)
8619 elem = (xmlNodePtr) attr;
8620 else
8621 elem = NULL;
8622 if (elem != NULL)
8623 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008624 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008625 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008626 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008627
William M. Brack76e95df2003-10-18 16:20:14 +00008628 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008629 ids = cur;
8630 }
8631 return(ret);
8632}
8633
8634/**
Owen Taylor3473f882001-02-23 17:55:21 +00008635 * xmlXPathIdFunction:
8636 * @ctxt: the XPath Parser context
8637 * @nargs: the number of arguments
8638 *
8639 * Implement the id() XPath function
8640 * node-set id(object)
8641 * The id function selects elements by their unique ID
8642 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8643 * then the result is the union of the result of applying id to the
8644 * string value of each of the nodes in the argument node-set. When the
8645 * argument to id is of any other type, the argument is converted to a
8646 * string as if by a call to the string function; the string is split
8647 * into a whitespace-separated list of tokens (whitespace is any sequence
8648 * of characters matching the production S); the result is a node-set
8649 * containing the elements in the same document as the context node that
8650 * have a unique ID equal to any of the tokens in the list.
8651 */
8652void
8653xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008654 xmlChar *tokens;
8655 xmlNodeSetPtr ret;
8656 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008657
8658 CHECK_ARITY(1);
8659 obj = valuePop(ctxt);
8660 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008661 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008662 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008663 int i;
8664
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008665 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008666 /*
8667 * FIXME -- in an out-of-memory condition this will behave badly.
8668 * The solution is not clear -- we already popped an item from
8669 * ctxt, so the object is in a corrupt state.
8670 */
Owen Taylor3473f882001-02-23 17:55:21 +00008671
Daniel Veillard911f49a2001-04-07 15:39:35 +00008672 if (obj->nodesetval != NULL) {
8673 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008674 tokens =
8675 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8676 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8677 ret = xmlXPathNodeSetMerge(ret, ns);
8678 xmlXPathFreeNodeSet(ns);
8679 if (tokens != NULL)
8680 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008681 }
Owen Taylor3473f882001-02-23 17:55:21 +00008682 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008683 xmlXPathReleaseObject(ctxt->context, obj);
8684 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008685 return;
8686 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008687 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008688 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008689 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008690 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008691 return;
8692}
8693
8694/**
8695 * xmlXPathLocalNameFunction:
8696 * @ctxt: the XPath Parser context
8697 * @nargs: the number of arguments
8698 *
8699 * Implement the local-name() XPath function
8700 * string local-name(node-set?)
8701 * The local-name function returns a string containing the local part
8702 * of the name of the node in the argument node-set that is first in
8703 * document order. If the node-set is empty or the first node has no
8704 * name, an empty string is returned. If the argument is omitted it
8705 * defaults to the context node.
8706 */
8707void
8708xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8709 xmlXPathObjectPtr cur;
8710
Daniel Veillarda82b1822004-11-08 16:24:57 +00008711 if (ctxt == NULL) return;
8712
Owen Taylor3473f882001-02-23 17:55:21 +00008713 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008714 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8715 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008716 nargs = 1;
8717 }
8718
8719 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008720 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008721 ((ctxt->value->type != XPATH_NODESET) &&
8722 (ctxt->value->type != XPATH_XSLT_TREE)))
8723 XP_ERROR(XPATH_INVALID_TYPE);
8724 cur = valuePop(ctxt);
8725
Daniel Veillard911f49a2001-04-07 15:39:35 +00008726 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008727 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008728 } else {
8729 int i = 0; /* Should be first in document order !!!!! */
8730 switch (cur->nodesetval->nodeTab[i]->type) {
8731 case XML_ELEMENT_NODE:
8732 case XML_ATTRIBUTE_NODE:
8733 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008734 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008735 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008736 else
8737 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008738 xmlXPathCacheNewString(ctxt->context,
8739 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008740 break;
8741 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008742 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008743 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8744 break;
8745 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008746 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008747 }
8748 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008749 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008750}
8751
8752/**
8753 * xmlXPathNamespaceURIFunction:
8754 * @ctxt: the XPath Parser context
8755 * @nargs: the number of arguments
8756 *
8757 * Implement the namespace-uri() XPath function
8758 * string namespace-uri(node-set?)
8759 * The namespace-uri function returns a string containing the
8760 * namespace URI of the expanded name of the node in the argument
8761 * node-set that is first in document order. If the node-set is empty,
8762 * the first node has no name, or the expanded name has no namespace
8763 * URI, an empty string is returned. If the argument is omitted it
8764 * defaults to the context node.
8765 */
8766void
8767xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8768 xmlXPathObjectPtr cur;
8769
Daniel Veillarda82b1822004-11-08 16:24:57 +00008770 if (ctxt == NULL) return;
8771
Owen Taylor3473f882001-02-23 17:55:21 +00008772 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008773 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8774 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008775 nargs = 1;
8776 }
8777 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008778 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008779 ((ctxt->value->type != XPATH_NODESET) &&
8780 (ctxt->value->type != XPATH_XSLT_TREE)))
8781 XP_ERROR(XPATH_INVALID_TYPE);
8782 cur = valuePop(ctxt);
8783
Daniel Veillard911f49a2001-04-07 15:39:35 +00008784 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008785 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008786 } else {
8787 int i = 0; /* Should be first in document order !!!!! */
8788 switch (cur->nodesetval->nodeTab[i]->type) {
8789 case XML_ELEMENT_NODE:
8790 case XML_ATTRIBUTE_NODE:
8791 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008792 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008793 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008794 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008795 cur->nodesetval->nodeTab[i]->ns->href));
8796 break;
8797 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008798 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008799 }
8800 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008801 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008802}
8803
8804/**
8805 * xmlXPathNameFunction:
8806 * @ctxt: the XPath Parser context
8807 * @nargs: the number of arguments
8808 *
8809 * Implement the name() XPath function
8810 * string name(node-set?)
8811 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008812 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008813 * order. The QName must represent the name with respect to the namespace
8814 * declarations in effect on the node whose name is being represented.
8815 * Typically, this will be the form in which the name occurred in the XML
8816 * source. This need not be the case if there are namespace declarations
8817 * in effect on the node that associate multiple prefixes with the same
8818 * namespace. However, an implementation may include information about
8819 * the original prefix in its representation of nodes; in this case, an
8820 * implementation can ensure that the returned string is always the same
8821 * as the QName used in the XML source. If the argument it omitted it
8822 * defaults to the context node.
8823 * Libxml keep the original prefix so the "real qualified name" used is
8824 * returned.
8825 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008826static void
Daniel Veillard04383752001-07-08 14:27:15 +00008827xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8828{
Owen Taylor3473f882001-02-23 17:55:21 +00008829 xmlXPathObjectPtr cur;
8830
8831 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008832 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8833 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008834 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008835 }
8836
8837 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008838 if ((ctxt->value == NULL) ||
8839 ((ctxt->value->type != XPATH_NODESET) &&
8840 (ctxt->value->type != XPATH_XSLT_TREE)))
8841 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008842 cur = valuePop(ctxt);
8843
Daniel Veillard911f49a2001-04-07 15:39:35 +00008844 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008845 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008846 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008847 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008848
Daniel Veillard04383752001-07-08 14:27:15 +00008849 switch (cur->nodesetval->nodeTab[i]->type) {
8850 case XML_ELEMENT_NODE:
8851 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008852 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008853 valuePush(ctxt,
8854 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008855 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8856 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008857 valuePush(ctxt,
8858 xmlXPathCacheNewString(ctxt->context,
8859 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008860 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008861 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008862
Daniel Veillardc00cda82003-04-07 10:22:39 +00008863 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8864 cur->nodesetval->nodeTab[i]->ns->prefix,
8865 NULL, 0);
8866 if (fullname == cur->nodesetval->nodeTab[i]->name)
8867 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8868 if (fullname == NULL) {
8869 XP_ERROR(XPATH_MEMORY_ERROR);
8870 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008871 valuePush(ctxt, xmlXPathCacheWrapString(
8872 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008873 }
8874 break;
8875 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008876 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8877 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008878 xmlXPathLocalNameFunction(ctxt, 1);
8879 }
Owen Taylor3473f882001-02-23 17:55:21 +00008880 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008881 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008882}
8883
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008884
8885/**
Owen Taylor3473f882001-02-23 17:55:21 +00008886 * xmlXPathStringFunction:
8887 * @ctxt: the XPath Parser context
8888 * @nargs: the number of arguments
8889 *
8890 * Implement the string() XPath function
8891 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008892 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008893 * - A node-set is converted to a string by returning the value of
8894 * the node in the node-set that is first in document order.
8895 * If the node-set is empty, an empty string is returned.
8896 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008897 * + NaN is converted to the string NaN
8898 * + positive zero is converted to the string 0
8899 * + negative zero is converted to the string 0
8900 * + positive infinity is converted to the string Infinity
8901 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008902 * + if the number is an integer, the number is represented in
8903 * decimal form as a Number with no decimal point and no leading
8904 * zeros, preceded by a minus sign (-) if the number is negative
8905 * + otherwise, the number is represented in decimal form as a
8906 * Number including a decimal point with at least one digit
8907 * before the decimal point and at least one digit after the
8908 * decimal point, preceded by a minus sign (-) if the number
8909 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008910 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008911 * before the decimal point; beyond the one required digit
8912 * after the decimal point there must be as many, but only as
8913 * many, more digits as are needed to uniquely distinguish the
8914 * number from all other IEEE 754 numeric values.
8915 * - The boolean false value is converted to the string false.
8916 * The boolean true value is converted to the string true.
8917 *
8918 * If the argument is omitted, it defaults to a node-set with the
8919 * context node as its only member.
8920 */
8921void
8922xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8923 xmlXPathObjectPtr cur;
8924
Daniel Veillarda82b1822004-11-08 16:24:57 +00008925 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008926 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008927 valuePush(ctxt,
8928 xmlXPathCacheWrapString(ctxt->context,
8929 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008930 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008931 }
8932
8933 CHECK_ARITY(1);
8934 cur = valuePop(ctxt);
8935 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008936 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008937}
8938
8939/**
8940 * xmlXPathStringLengthFunction:
8941 * @ctxt: the XPath Parser context
8942 * @nargs: the number of arguments
8943 *
8944 * Implement the string-length() XPath function
8945 * number string-length(string?)
8946 * The string-length returns the number of characters in the string
8947 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8948 * the context node converted to a string, in other words the value
8949 * of the context node.
8950 */
8951void
8952xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8953 xmlXPathObjectPtr cur;
8954
8955 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008956 if ((ctxt == NULL) || (ctxt->context == NULL))
8957 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008958 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008959 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008960 } else {
8961 xmlChar *content;
8962
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008963 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008964 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8965 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008966 xmlFree(content);
8967 }
8968 return;
8969 }
8970 CHECK_ARITY(1);
8971 CAST_TO_STRING;
8972 CHECK_TYPE(XPATH_STRING);
8973 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008974 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008975 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008976 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008977}
8978
8979/**
8980 * xmlXPathConcatFunction:
8981 * @ctxt: the XPath Parser context
8982 * @nargs: the number of arguments
8983 *
8984 * Implement the concat() XPath function
8985 * string concat(string, string, string*)
8986 * The concat function returns the concatenation of its arguments.
8987 */
8988void
8989xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8990 xmlXPathObjectPtr cur, newobj;
8991 xmlChar *tmp;
8992
Daniel Veillarda82b1822004-11-08 16:24:57 +00008993 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008994 if (nargs < 2) {
8995 CHECK_ARITY(2);
8996 }
8997
8998 CAST_TO_STRING;
8999 cur = valuePop(ctxt);
9000 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009001 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009002 return;
9003 }
9004 nargs--;
9005
9006 while (nargs > 0) {
9007 CAST_TO_STRING;
9008 newobj = valuePop(ctxt);
9009 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009010 xmlXPathReleaseObject(ctxt->context, newobj);
9011 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009012 XP_ERROR(XPATH_INVALID_TYPE);
9013 }
9014 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9015 newobj->stringval = cur->stringval;
9016 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009017 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00009018 nargs--;
9019 }
9020 valuePush(ctxt, cur);
9021}
9022
9023/**
9024 * xmlXPathContainsFunction:
9025 * @ctxt: the XPath Parser context
9026 * @nargs: the number of arguments
9027 *
9028 * Implement the contains() XPath function
9029 * boolean contains(string, string)
9030 * The contains function returns true if the first argument string
9031 * contains the second argument string, and otherwise returns false.
9032 */
9033void
9034xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9035 xmlXPathObjectPtr hay, needle;
9036
9037 CHECK_ARITY(2);
9038 CAST_TO_STRING;
9039 CHECK_TYPE(XPATH_STRING);
9040 needle = valuePop(ctxt);
9041 CAST_TO_STRING;
9042 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009043
Owen Taylor3473f882001-02-23 17:55:21 +00009044 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009045 xmlXPathReleaseObject(ctxt->context, hay);
9046 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009047 XP_ERROR(XPATH_INVALID_TYPE);
9048 }
9049 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009050 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009051 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009052 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9053 xmlXPathReleaseObject(ctxt->context, hay);
9054 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009055}
9056
9057/**
9058 * xmlXPathStartsWithFunction:
9059 * @ctxt: the XPath Parser context
9060 * @nargs: the number of arguments
9061 *
9062 * Implement the starts-with() XPath function
9063 * boolean starts-with(string, string)
9064 * The starts-with function returns true if the first argument string
9065 * starts with the second argument string, and otherwise returns false.
9066 */
9067void
9068xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9069 xmlXPathObjectPtr hay, needle;
9070 int n;
9071
9072 CHECK_ARITY(2);
9073 CAST_TO_STRING;
9074 CHECK_TYPE(XPATH_STRING);
9075 needle = valuePop(ctxt);
9076 CAST_TO_STRING;
9077 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009078
Owen Taylor3473f882001-02-23 17:55:21 +00009079 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009080 xmlXPathReleaseObject(ctxt->context, hay);
9081 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009082 XP_ERROR(XPATH_INVALID_TYPE);
9083 }
9084 n = xmlStrlen(needle->stringval);
9085 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009086 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009087 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009088 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9089 xmlXPathReleaseObject(ctxt->context, hay);
9090 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009091}
9092
9093/**
9094 * xmlXPathSubstringFunction:
9095 * @ctxt: the XPath Parser context
9096 * @nargs: the number of arguments
9097 *
9098 * Implement the substring() XPath function
9099 * string substring(string, number, number?)
9100 * The substring function returns the substring of the first argument
9101 * starting at the position specified in the second argument with
9102 * length specified in the third argument. For example,
9103 * substring("12345",2,3) returns "234". If the third argument is not
9104 * specified, it returns the substring starting at the position specified
9105 * in the second argument and continuing to the end of the string. For
9106 * example, substring("12345",2) returns "2345". More precisely, each
9107 * character in the string (see [3.6 Strings]) is considered to have a
9108 * numeric position: the position of the first character is 1, the position
9109 * of the second character is 2 and so on. The returned substring contains
9110 * those characters for which the position of the character is greater than
9111 * or equal to the second argument and, if the third argument is specified,
9112 * less than the sum of the second and third arguments; the comparisons
9113 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009114 * - substring("12345", 1.5, 2.6) returns "234"
9115 * - substring("12345", 0, 3) returns "12"
9116 * - substring("12345", 0 div 0, 3) returns ""
9117 * - substring("12345", 1, 0 div 0) returns ""
9118 * - substring("12345", -42, 1 div 0) returns "12345"
9119 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009120 */
9121void
9122xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9123 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009124 double le=0, in;
9125 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009126 xmlChar *ret;
9127
Owen Taylor3473f882001-02-23 17:55:21 +00009128 if (nargs < 2) {
9129 CHECK_ARITY(2);
9130 }
9131 if (nargs > 3) {
9132 CHECK_ARITY(3);
9133 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009134 /*
9135 * take care of possible last (position) argument
9136 */
Owen Taylor3473f882001-02-23 17:55:21 +00009137 if (nargs == 3) {
9138 CAST_TO_NUMBER;
9139 CHECK_TYPE(XPATH_NUMBER);
9140 len = valuePop(ctxt);
9141 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009142 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009143 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009144
Owen Taylor3473f882001-02-23 17:55:21 +00009145 CAST_TO_NUMBER;
9146 CHECK_TYPE(XPATH_NUMBER);
9147 start = valuePop(ctxt);
9148 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009149 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009150 CAST_TO_STRING;
9151 CHECK_TYPE(XPATH_STRING);
9152 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009153 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009154
Daniel Veillard97ac1312001-05-30 19:14:17 +00009155 /*
9156 * If last pos not present, calculate last position
9157 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009158 if (nargs != 3) {
9159 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009160 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009161 in = 1.0;
9162 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009163
Daniel Veillard45490ae2008-07-29 09:13:19 +00009164 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009165 * the index is NaN, the length is NaN, or both
9166 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009167 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009168 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009169 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009170 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009171 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009172 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009173 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009174 * First we go to integer form, rounding up
9175 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009176 */
9177 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009178 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009179
Daniel Veillard9e412302002-06-10 15:59:44 +00009180 if (xmlXPathIsInf(le) == 1) {
9181 l = m;
9182 if (i < 1)
9183 i = 1;
9184 }
9185 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9186 l = 0;
9187 else {
9188 l = (int) le;
9189 if (((double)l)+0.5 <= le) l++;
9190 }
9191
9192 /* Now we normalize inidices */
9193 i -= 1;
9194 l += i;
9195 if (i < 0)
9196 i = 0;
9197 if (l > m)
9198 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009199
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009200 /* number of chars to copy */
9201 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009202
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009203 ret = xmlUTF8Strsub(str->stringval, i, l);
9204 }
9205 else {
9206 ret = NULL;
9207 }
Owen Taylor3473f882001-02-23 17:55:21 +00009208 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009209 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009210 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009211 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009212 xmlFree(ret);
9213 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009214 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009215}
9216
9217/**
9218 * xmlXPathSubstringBeforeFunction:
9219 * @ctxt: the XPath Parser context
9220 * @nargs: the number of arguments
9221 *
9222 * Implement the substring-before() XPath function
9223 * string substring-before(string, string)
9224 * The substring-before function returns the substring of the first
9225 * argument string that precedes the first occurrence of the second
9226 * argument string in the first argument string, or the empty string
9227 * if the first argument string does not contain the second argument
9228 * string. For example, substring-before("1999/04/01","/") returns 1999.
9229 */
9230void
9231xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9232 xmlXPathObjectPtr str;
9233 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009234 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009235 const xmlChar *point;
9236 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009237
Owen Taylor3473f882001-02-23 17:55:21 +00009238 CHECK_ARITY(2);
9239 CAST_TO_STRING;
9240 find = valuePop(ctxt);
9241 CAST_TO_STRING;
9242 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009243
Daniel Veillardade10f22012-07-12 09:43:27 +08009244 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009245 if (target) {
9246 point = xmlStrstr(str->stringval, find->stringval);
9247 if (point) {
9248 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009249 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009250 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009251 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009252 xmlBufContent(target)));
9253 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009254 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009255 xmlXPathReleaseObject(ctxt->context, str);
9256 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009257}
9258
9259/**
9260 * xmlXPathSubstringAfterFunction:
9261 * @ctxt: the XPath Parser context
9262 * @nargs: the number of arguments
9263 *
9264 * Implement the substring-after() XPath function
9265 * string substring-after(string, string)
9266 * The substring-after function returns the substring of the first
9267 * argument string that follows the first occurrence of the second
9268 * argument string in the first argument string, or the empty stringi
9269 * if the first argument string does not contain the second argument
9270 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9271 * and substring-after("1999/04/01","19") returns 99/04/01.
9272 */
9273void
9274xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9275 xmlXPathObjectPtr str;
9276 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009277 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009278 const xmlChar *point;
9279 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009280
Owen Taylor3473f882001-02-23 17:55:21 +00009281 CHECK_ARITY(2);
9282 CAST_TO_STRING;
9283 find = valuePop(ctxt);
9284 CAST_TO_STRING;
9285 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009286
Daniel Veillardade10f22012-07-12 09:43:27 +08009287 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009288 if (target) {
9289 point = xmlStrstr(str->stringval, find->stringval);
9290 if (point) {
9291 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009292 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009293 xmlStrlen(str->stringval) - offset);
9294 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009295 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009296 xmlBufContent(target)));
9297 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009298 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009299 xmlXPathReleaseObject(ctxt->context, str);
9300 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009301}
9302
9303/**
9304 * xmlXPathNormalizeFunction:
9305 * @ctxt: the XPath Parser context
9306 * @nargs: the number of arguments
9307 *
9308 * Implement the normalize-space() XPath function
9309 * string normalize-space(string?)
9310 * The normalize-space function returns the argument string with white
9311 * space normalized by stripping leading and trailing whitespace
9312 * and replacing sequences of whitespace characters by a single
9313 * space. Whitespace characters are the same allowed by the S production
9314 * in XML. If the argument is omitted, it defaults to the context
9315 * node converted to a string, in other words the value of the context node.
9316 */
9317void
9318xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9319 xmlXPathObjectPtr obj = NULL;
9320 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009321 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009322 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009323
Daniel Veillarda82b1822004-11-08 16:24:57 +00009324 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009325 if (nargs == 0) {
9326 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009327 valuePush(ctxt,
9328 xmlXPathCacheWrapString(ctxt->context,
9329 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009330 nargs = 1;
9331 }
9332
9333 CHECK_ARITY(1);
9334 CAST_TO_STRING;
9335 CHECK_TYPE(XPATH_STRING);
9336 obj = valuePop(ctxt);
9337 source = obj->stringval;
9338
Daniel Veillardade10f22012-07-12 09:43:27 +08009339 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009340 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009341
Owen Taylor3473f882001-02-23 17:55:21 +00009342 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009343 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009344 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009345
Owen Taylor3473f882001-02-23 17:55:21 +00009346 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9347 blank = 0;
9348 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009349 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009350 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009351 } else {
9352 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009353 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009354 blank = 0;
9355 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009356 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009357 }
9358 source++;
9359 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009360 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009361 xmlBufContent(target)));
9362 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009363 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009364 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009365}
9366
9367/**
9368 * xmlXPathTranslateFunction:
9369 * @ctxt: the XPath Parser context
9370 * @nargs: the number of arguments
9371 *
9372 * Implement the translate() XPath function
9373 * string translate(string, string, string)
9374 * The translate function returns the first argument string with
9375 * occurrences of characters in the second argument string replaced
9376 * by the character at the corresponding position in the third argument
9377 * string. For example, translate("bar","abc","ABC") returns the string
9378 * BAr. If there is a character in the second argument string with no
9379 * character at a corresponding position in the third argument string
9380 * (because the second argument string is longer than the third argument
9381 * string), then occurrences of that character in the first argument
9382 * string are removed. For example, translate("--aaa--","abc-","ABC")
9383 * returns "AAA". If a character occurs more than once in second
9384 * argument string, then the first occurrence determines the replacement
9385 * character. If the third argument string is longer than the second
9386 * argument string, then excess characters are ignored.
9387 */
9388void
9389xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009390 xmlXPathObjectPtr str;
9391 xmlXPathObjectPtr from;
9392 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009393 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009394 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009395 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009396 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009397 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009398
Daniel Veillarde043ee12001-04-16 14:08:07 +00009399 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009400
Daniel Veillarde043ee12001-04-16 14:08:07 +00009401 CAST_TO_STRING;
9402 to = valuePop(ctxt);
9403 CAST_TO_STRING;
9404 from = valuePop(ctxt);
9405 CAST_TO_STRING;
9406 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009407
Daniel Veillardade10f22012-07-12 09:43:27 +08009408 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009409 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009410 max = xmlUTF8Strlen(to->stringval);
9411 for (cptr = str->stringval; (ch=*cptr); ) {
9412 offset = xmlUTF8Strloc(from->stringval, cptr);
9413 if (offset >= 0) {
9414 if (offset < max) {
9415 point = xmlUTF8Strpos(to->stringval, offset);
9416 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009417 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009418 }
9419 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009420 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009421
9422 /* Step to next character in input */
9423 cptr++;
9424 if ( ch & 0x80 ) {
9425 /* if not simple ascii, verify proper format */
9426 if ( (ch & 0xc0) != 0xc0 ) {
9427 xmlGenericError(xmlGenericErrorContext,
9428 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009429 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009430 break;
9431 }
9432 /* then skip over remaining bytes for this char */
9433 while ( (ch <<= 1) & 0x80 )
9434 if ( (*cptr++ & 0xc0) != 0x80 ) {
9435 xmlGenericError(xmlGenericErrorContext,
9436 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009437 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009438 break;
9439 }
9440 if (ch & 0x80) /* must have had error encountered */
9441 break;
9442 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009443 }
Owen Taylor3473f882001-02-23 17:55:21 +00009444 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009445 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009446 xmlBufContent(target)));
9447 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009448 xmlXPathReleaseObject(ctxt->context, str);
9449 xmlXPathReleaseObject(ctxt->context, from);
9450 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009451}
9452
9453/**
9454 * xmlXPathBooleanFunction:
9455 * @ctxt: the XPath Parser context
9456 * @nargs: the number of arguments
9457 *
9458 * Implement the boolean() XPath function
9459 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009460 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009461 * - a number is true if and only if it is neither positive or
9462 * negative zero nor NaN
9463 * - a node-set is true if and only if it is non-empty
9464 * - a string is true if and only if its length is non-zero
9465 */
9466void
9467xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9468 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009469
9470 CHECK_ARITY(1);
9471 cur = valuePop(ctxt);
9472 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009473 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009474 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009475}
9476
9477/**
9478 * xmlXPathNotFunction:
9479 * @ctxt: the XPath Parser context
9480 * @nargs: the number of arguments
9481 *
9482 * Implement the not() XPath function
9483 * boolean not(boolean)
9484 * The not function returns true if its argument is false,
9485 * and false otherwise.
9486 */
9487void
9488xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9489 CHECK_ARITY(1);
9490 CAST_TO_BOOLEAN;
9491 CHECK_TYPE(XPATH_BOOLEAN);
9492 ctxt->value->boolval = ! ctxt->value->boolval;
9493}
9494
9495/**
9496 * xmlXPathTrueFunction:
9497 * @ctxt: the XPath Parser context
9498 * @nargs: the number of arguments
9499 *
9500 * Implement the true() XPath function
9501 * boolean true()
9502 */
9503void
9504xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9505 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009506 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009507}
9508
9509/**
9510 * xmlXPathFalseFunction:
9511 * @ctxt: the XPath Parser context
9512 * @nargs: the number of arguments
9513 *
9514 * Implement the false() XPath function
9515 * boolean false()
9516 */
9517void
9518xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9519 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009520 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009521}
9522
9523/**
9524 * xmlXPathLangFunction:
9525 * @ctxt: the XPath Parser context
9526 * @nargs: the number of arguments
9527 *
9528 * Implement the lang() XPath function
9529 * boolean lang(string)
9530 * The lang function returns true or false depending on whether the
9531 * language of the context node as specified by xml:lang attributes
9532 * is the same as or is a sublanguage of the language specified by
9533 * the argument string. The language of the context node is determined
9534 * by the value of the xml:lang attribute on the context node, or, if
9535 * the context node has no xml:lang attribute, by the value of the
9536 * xml:lang attribute on the nearest ancestor of the context node that
9537 * has an xml:lang attribute. If there is no such attribute, then lang
9538 * returns false. If there is such an attribute, then lang returns
9539 * true if the attribute value is equal to the argument ignoring case,
9540 * or if there is some suffix starting with - such that the attribute
9541 * value is equal to the argument ignoring that suffix of the attribute
9542 * value and ignoring case.
9543 */
9544void
9545xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009546 xmlXPathObjectPtr val = NULL;
9547 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009548 const xmlChar *lang;
9549 int ret = 0;
9550 int i;
9551
9552 CHECK_ARITY(1);
9553 CAST_TO_STRING;
9554 CHECK_TYPE(XPATH_STRING);
9555 val = valuePop(ctxt);
9556 lang = val->stringval;
9557 theLang = xmlNodeGetLang(ctxt->context->node);
9558 if ((theLang != NULL) && (lang != NULL)) {
9559 for (i = 0;lang[i] != 0;i++)
9560 if (toupper(lang[i]) != toupper(theLang[i]))
9561 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009562 if ((theLang[i] == 0) || (theLang[i] == '-'))
9563 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009564 }
9565not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009566 if (theLang != NULL)
9567 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009568
9569 xmlXPathReleaseObject(ctxt->context, val);
9570 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009571}
9572
9573/**
9574 * xmlXPathNumberFunction:
9575 * @ctxt: the XPath Parser context
9576 * @nargs: the number of arguments
9577 *
9578 * Implement the number() XPath function
9579 * number number(object?)
9580 */
9581void
9582xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9583 xmlXPathObjectPtr cur;
9584 double res;
9585
Daniel Veillarda82b1822004-11-08 16:24:57 +00009586 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009587 if (nargs == 0) {
9588 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009589 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009590 } else {
9591 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9592
9593 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009594 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009595 xmlFree(content);
9596 }
9597 return;
9598 }
9599
9600 CHECK_ARITY(1);
9601 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009602 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009603}
9604
9605/**
9606 * xmlXPathSumFunction:
9607 * @ctxt: the XPath Parser context
9608 * @nargs: the number of arguments
9609 *
9610 * Implement the sum() XPath function
9611 * number sum(node-set)
9612 * The sum function returns the sum of the values of the nodes in
9613 * the argument node-set.
9614 */
9615void
9616xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9617 xmlXPathObjectPtr cur;
9618 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009619 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009620
9621 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009622 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009623 ((ctxt->value->type != XPATH_NODESET) &&
9624 (ctxt->value->type != XPATH_XSLT_TREE)))
9625 XP_ERROR(XPATH_INVALID_TYPE);
9626 cur = valuePop(ctxt);
9627
William M. Brack08171912003-12-29 02:52:11 +00009628 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009629 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9630 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009631 }
9632 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009633 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9634 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009635}
9636
William M. Brack3d426662005-04-19 14:40:28 +00009637/*
9638 * To assure working code on multiple platforms, we want to only depend
9639 * upon the characteristic truncation of converting a floating point value
9640 * to an integer. Unfortunately, because of the different storage sizes
9641 * of our internal floating point value (double) and integer (int), we
9642 * can't directly convert (see bug 301162). This macro is a messy
9643 * 'workaround'
9644 */
9645#define XTRUNC(f, v) \
9646 f = fmod((v), INT_MAX); \
9647 f = (v) - (f) + (double)((int)(f));
9648
Owen Taylor3473f882001-02-23 17:55:21 +00009649/**
9650 * xmlXPathFloorFunction:
9651 * @ctxt: the XPath Parser context
9652 * @nargs: the number of arguments
9653 *
9654 * Implement the floor() XPath function
9655 * number floor(number)
9656 * The floor function returns the largest (closest to positive infinity)
9657 * number that is not greater than the argument and that is an integer.
9658 */
9659void
9660xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009661 double f;
9662
Owen Taylor3473f882001-02-23 17:55:21 +00009663 CHECK_ARITY(1);
9664 CAST_TO_NUMBER;
9665 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009666
William M. Brack3d426662005-04-19 14:40:28 +00009667 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009668 if (f != ctxt->value->floatval) {
9669 if (ctxt->value->floatval > 0)
9670 ctxt->value->floatval = f;
9671 else
9672 ctxt->value->floatval = f - 1;
9673 }
Owen Taylor3473f882001-02-23 17:55:21 +00009674}
9675
9676/**
9677 * xmlXPathCeilingFunction:
9678 * @ctxt: the XPath Parser context
9679 * @nargs: the number of arguments
9680 *
9681 * Implement the ceiling() XPath function
9682 * number ceiling(number)
9683 * The ceiling function returns the smallest (closest to negative infinity)
9684 * number that is not less than the argument and that is an integer.
9685 */
9686void
9687xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9688 double f;
9689
9690 CHECK_ARITY(1);
9691 CAST_TO_NUMBER;
9692 CHECK_TYPE(XPATH_NUMBER);
9693
9694#if 0
9695 ctxt->value->floatval = ceil(ctxt->value->floatval);
9696#else
William M. Brack3d426662005-04-19 14:40:28 +00009697 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009698 if (f != ctxt->value->floatval) {
9699 if (ctxt->value->floatval > 0)
9700 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009701 else {
9702 if (ctxt->value->floatval < 0 && f == 0)
9703 ctxt->value->floatval = xmlXPathNZERO;
9704 else
9705 ctxt->value->floatval = f;
9706 }
9707
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009708 }
Owen Taylor3473f882001-02-23 17:55:21 +00009709#endif
9710}
9711
9712/**
9713 * xmlXPathRoundFunction:
9714 * @ctxt: the XPath Parser context
9715 * @nargs: the number of arguments
9716 *
9717 * Implement the round() XPath function
9718 * number round(number)
9719 * The round function returns the number that is closest to the
9720 * argument and that is an integer. If there are two such numbers,
9721 * then the one that is even is returned.
9722 */
9723void
9724xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9725 double f;
9726
9727 CHECK_ARITY(1);
9728 CAST_TO_NUMBER;
9729 CHECK_TYPE(XPATH_NUMBER);
9730
Daniel Veillardcda96922001-08-21 10:56:31 +00009731 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9732 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9733 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009734 (ctxt->value->floatval == 0.0))
9735 return;
9736
William M. Brack3d426662005-04-19 14:40:28 +00009737 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009738 if (ctxt->value->floatval < 0) {
9739 if (ctxt->value->floatval < f - 0.5)
9740 ctxt->value->floatval = f - 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009741 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009742 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009743 if (ctxt->value->floatval == 0)
9744 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009745 } else {
9746 if (ctxt->value->floatval < f + 0.5)
9747 ctxt->value->floatval = f;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009748 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009749 ctxt->value->floatval = f + 1;
9750 }
Owen Taylor3473f882001-02-23 17:55:21 +00009751}
9752
9753/************************************************************************
9754 * *
9755 * The Parser *
9756 * *
9757 ************************************************************************/
9758
9759/*
William M. Brack08171912003-12-29 02:52:11 +00009760 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009761 * implementation.
9762 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009763static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009764static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009765static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009766static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009767static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9768 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009769
9770/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009771 * xmlXPathCurrentChar:
9772 * @ctxt: the XPath parser context
9773 * @cur: pointer to the beginning of the char
9774 * @len: pointer to the length of the char read
9775 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009776 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009777 * bytes in the input buffer.
9778 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009779 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009780 */
9781
9782static int
9783xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9784 unsigned char c;
9785 unsigned int val;
9786 const xmlChar *cur;
9787
9788 if (ctxt == NULL)
9789 return(0);
9790 cur = ctxt->cur;
9791
9792 /*
9793 * We are supposed to handle UTF8, check it's valid
9794 * From rfc2044: encoding of the Unicode values on UTF-8:
9795 *
9796 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9797 * 0000 0000-0000 007F 0xxxxxxx
9798 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009799 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009800 *
9801 * Check for the 0x110000 limit too
9802 */
9803 c = *cur;
9804 if (c & 0x80) {
9805 if ((cur[1] & 0xc0) != 0x80)
9806 goto encoding_error;
9807 if ((c & 0xe0) == 0xe0) {
9808
9809 if ((cur[2] & 0xc0) != 0x80)
9810 goto encoding_error;
9811 if ((c & 0xf0) == 0xf0) {
9812 if (((c & 0xf8) != 0xf0) ||
9813 ((cur[3] & 0xc0) != 0x80))
9814 goto encoding_error;
9815 /* 4-byte code */
9816 *len = 4;
9817 val = (cur[0] & 0x7) << 18;
9818 val |= (cur[1] & 0x3f) << 12;
9819 val |= (cur[2] & 0x3f) << 6;
9820 val |= cur[3] & 0x3f;
9821 } else {
9822 /* 3-byte code */
9823 *len = 3;
9824 val = (cur[0] & 0xf) << 12;
9825 val |= (cur[1] & 0x3f) << 6;
9826 val |= cur[2] & 0x3f;
9827 }
9828 } else {
9829 /* 2-byte code */
9830 *len = 2;
9831 val = (cur[0] & 0x1f) << 6;
9832 val |= cur[1] & 0x3f;
9833 }
9834 if (!IS_CHAR(val)) {
9835 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009836 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009837 return(val);
9838 } else {
9839 /* 1-byte code */
9840 *len = 1;
9841 return((int) *cur);
9842 }
9843encoding_error:
9844 /*
William M. Brack08171912003-12-29 02:52:11 +00009845 * If we detect an UTF8 error that probably means that the
9846 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009847 * declaration header. Report the error and switch the encoding
9848 * to ISO-Latin-1 (if you don't like this policy, just declare the
9849 * encoding !)
9850 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009851 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009852 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009853}
9854
9855/**
Owen Taylor3473f882001-02-23 17:55:21 +00009856 * xmlXPathParseNCName:
9857 * @ctxt: the XPath Parser context
9858 *
9859 * parse an XML namespace non qualified name.
9860 *
9861 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9862 *
9863 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9864 * CombiningChar | Extender
9865 *
9866 * Returns the namespace name or NULL
9867 */
9868
9869xmlChar *
9870xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009871 const xmlChar *in;
9872 xmlChar *ret;
9873 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009874
Daniel Veillarda82b1822004-11-08 16:24:57 +00009875 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009876 /*
9877 * Accelerator for simple ASCII names
9878 */
9879 in = ctxt->cur;
9880 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9881 ((*in >= 0x41) && (*in <= 0x5A)) ||
9882 (*in == '_')) {
9883 in++;
9884 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9885 ((*in >= 0x41) && (*in <= 0x5A)) ||
9886 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009887 (*in == '_') || (*in == '.') ||
9888 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009889 in++;
9890 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9891 (*in == '[') || (*in == ']') || (*in == ':') ||
9892 (*in == '@') || (*in == '*')) {
9893 count = in - ctxt->cur;
9894 if (count == 0)
9895 return(NULL);
9896 ret = xmlStrndup(ctxt->cur, count);
9897 ctxt->cur = in;
9898 return(ret);
9899 }
9900 }
9901 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009902}
9903
Daniel Veillard2156a562001-04-28 12:24:34 +00009904
Owen Taylor3473f882001-02-23 17:55:21 +00009905/**
9906 * xmlXPathParseQName:
9907 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009908 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009909 *
9910 * parse an XML qualified name
9911 *
9912 * [NS 5] QName ::= (Prefix ':')? LocalPart
9913 *
9914 * [NS 6] Prefix ::= NCName
9915 *
9916 * [NS 7] LocalPart ::= NCName
9917 *
9918 * Returns the function returns the local part, and prefix is updated
9919 * to get the Prefix if any.
9920 */
9921
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009922static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009923xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9924 xmlChar *ret = NULL;
9925
9926 *prefix = NULL;
9927 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009928 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009929 *prefix = ret;
9930 NEXT;
9931 ret = xmlXPathParseNCName(ctxt);
9932 }
9933 return(ret);
9934}
9935
9936/**
9937 * xmlXPathParseName:
9938 * @ctxt: the XPath Parser context
9939 *
9940 * parse an XML name
9941 *
9942 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9943 * CombiningChar | Extender
9944 *
9945 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9946 *
9947 * Returns the namespace name or NULL
9948 */
9949
9950xmlChar *
9951xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009952 const xmlChar *in;
9953 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009954 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009955
Daniel Veillarda82b1822004-11-08 16:24:57 +00009956 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009957 /*
9958 * Accelerator for simple ASCII names
9959 */
9960 in = ctxt->cur;
9961 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9962 ((*in >= 0x41) && (*in <= 0x5A)) ||
9963 (*in == '_') || (*in == ':')) {
9964 in++;
9965 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9966 ((*in >= 0x41) && (*in <= 0x5A)) ||
9967 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009968 (*in == '_') || (*in == '-') ||
9969 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009970 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009971 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009972 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009973 if (count > XML_MAX_NAME_LENGTH) {
9974 ctxt->cur = in;
9975 XP_ERRORNULL(XPATH_EXPR_ERROR);
9976 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009977 ret = xmlStrndup(ctxt->cur, count);
9978 ctxt->cur = in;
9979 return(ret);
9980 }
9981 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009982 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009983}
9984
Daniel Veillard61d80a22001-04-27 17:13:01 +00009985static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009986xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009987 xmlChar buf[XML_MAX_NAMELEN + 5];
9988 int len = 0, l;
9989 int c;
9990
9991 /*
9992 * Handler for more complex cases
9993 */
9994 c = CUR_CHAR(l);
9995 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009996 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9997 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009998 (!IS_LETTER(c) && (c != '_') &&
Xin Li28c53d32017-03-07 00:33:02 +00009999 ((!qualified) || (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +000010000 return(NULL);
10001 }
10002
10003 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10004 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10005 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010006 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +000010007 (IS_COMBINING(c)) ||
10008 (IS_EXTENDER(c)))) {
10009 COPY_BUF(l,buf,len,c);
10010 NEXTL(l);
10011 c = CUR_CHAR(l);
10012 if (len >= XML_MAX_NAMELEN) {
10013 /*
10014 * Okay someone managed to make a huge name, so he's ready to pay
10015 * for the processing speed.
10016 */
10017 xmlChar *buffer;
10018 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010019
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010020 if (len > XML_MAX_NAME_LENGTH) {
10021 XP_ERRORNULL(XPATH_EXPR_ERROR);
10022 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +000010023 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010024 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010025 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010026 }
10027 memcpy(buffer, buf, len);
10028 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10029 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010030 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +000010031 (IS_COMBINING(c)) ||
10032 (IS_EXTENDER(c))) {
10033 if (len + 10 > max) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010034 if (max > XML_MAX_NAME_LENGTH) {
10035 XP_ERRORNULL(XPATH_EXPR_ERROR);
10036 }
Daniel Veillard61d80a22001-04-27 17:13:01 +000010037 max *= 2;
10038 buffer = (xmlChar *) xmlRealloc(buffer,
10039 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010040 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010041 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010042 }
10043 }
10044 COPY_BUF(l,buffer,len,c);
10045 NEXTL(l);
10046 c = CUR_CHAR(l);
10047 }
10048 buffer[len] = 0;
10049 return(buffer);
10050 }
10051 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010052 if (len == 0)
10053 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010054 return(xmlStrndup(buf, len));
10055}
Daniel Veillard3cd72402002-05-13 10:33:30 +000010056
10057#define MAX_FRAC 20
10058
William M. Brack372a4452004-02-17 13:09:23 +000010059/*
10060 * These are used as divisors for the fractional part of a number.
10061 * Since the table includes 1.0 (representing '0' fractional digits),
10062 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10063 */
10064static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010065 1.0, 10.0, 100.0, 1000.0, 10000.0,
10066 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10067 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10068 100000000000000.0,
10069 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +000010070 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +000010071};
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 == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010135 int v, frac = 0;
10136 double fraction = 0;
10137
Owen Taylor3473f882001-02-23 17:55:21 +000010138 cur++;
10139 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10140 return(xmlXPathNAN);
10141 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010142 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10143 v = (*cur - '0');
10144 fraction = fraction * 10 + v;
10145 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010146 cur++;
10147 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010148 fraction /= my_pow10[frac];
10149 ret = ret + fraction;
10150 while ((*cur >= '0') && (*cur <= '9'))
10151 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010152 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010153 if ((*cur == 'e') || (*cur == 'E')) {
10154 cur++;
10155 if (*cur == '-') {
10156 is_exponent_negative = 1;
10157 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010158 } else if (*cur == '+') {
10159 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010160 }
10161 while ((*cur >= '0') && (*cur <= '9')) {
10162 exponent = exponent * 10 + (*cur - '0');
10163 cur++;
10164 }
10165 }
William M. Brack76e95df2003-10-18 16:20:14 +000010166 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010167 if (*cur != 0) return(xmlXPathNAN);
10168 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010169 if (is_exponent_negative) exponent = -exponent;
10170 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010171 return(ret);
10172}
10173
10174/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010175 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010176 * @ctxt: the XPath Parser context
10177 *
10178 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010179 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010180 * [31] Digits ::= [0-9]+
10181 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010182 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010183 *
10184 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010185static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010186xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10187{
Owen Taylor3473f882001-02-23 17:55:21 +000010188 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010189 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010190 int exponent = 0;
10191 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010192#ifdef __GNUC__
10193 unsigned long tmp = 0;
10194 double temp;
10195#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010196
10197 CHECK_ERROR;
10198 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10199 XP_ERROR(XPATH_NUMBER_ERROR);
10200 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010201#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010202 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010203 * tmp/temp is a workaround against a gcc compiler bug
10204 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010205 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010206 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010207 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010208 ret = ret * 10;
10209 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010210 ok = 1;
10211 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010212 temp = (double) tmp;
10213 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010214 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010215#else
10216 ret = 0;
10217 while ((CUR >= '0') && (CUR <= '9')) {
10218 ret = ret * 10 + (CUR - '0');
10219 ok = 1;
10220 NEXT;
10221 }
10222#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010223 if (CUR == '.') {
Phil Shaferee32ad32010-11-03 20:53:55 +010010224 int v, frac = 0;
10225 double fraction = 0;
10226
Owen Taylor3473f882001-02-23 17:55:21 +000010227 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010228 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10229 XP_ERROR(XPATH_NUMBER_ERROR);
10230 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010231 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10232 v = (CUR - '0');
10233 fraction = fraction * 10 + v;
10234 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010235 NEXT;
10236 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010237 fraction /= my_pow10[frac];
10238 ret = ret + fraction;
10239 while ((CUR >= '0') && (CUR <= '9'))
10240 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010241 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010242 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010243 NEXT;
10244 if (CUR == '-') {
10245 is_exponent_negative = 1;
10246 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010247 } else if (CUR == '+') {
10248 NEXT;
10249 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010250 while ((CUR >= '0') && (CUR <= '9')) {
10251 exponent = exponent * 10 + (CUR - '0');
10252 NEXT;
10253 }
10254 if (is_exponent_negative)
10255 exponent = -exponent;
10256 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010257 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010258 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010259 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010260}
10261
10262/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010263 * xmlXPathParseLiteral:
10264 * @ctxt: the XPath Parser context
10265 *
10266 * Parse a Literal
10267 *
10268 * [29] Literal ::= '"' [^"]* '"'
10269 * | "'" [^']* "'"
10270 *
10271 * Returns the value found or NULL in case of error
10272 */
10273static xmlChar *
10274xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10275 const xmlChar *q;
10276 xmlChar *ret = NULL;
10277
10278 if (CUR == '"') {
10279 NEXT;
10280 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010281 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010282 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010283 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010284 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010285 } else {
10286 ret = xmlStrndup(q, CUR_PTR - q);
10287 NEXT;
10288 }
10289 } else if (CUR == '\'') {
10290 NEXT;
10291 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010292 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010293 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010294 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010295 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010296 } else {
10297 ret = xmlStrndup(q, CUR_PTR - q);
10298 NEXT;
10299 }
10300 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010301 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010302 }
10303 return(ret);
10304}
10305
10306/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010307 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010308 * @ctxt: the XPath Parser context
10309 *
10310 * Parse a Literal and push it on the stack.
10311 *
10312 * [29] Literal ::= '"' [^"]* '"'
10313 * | "'" [^']* "'"
10314 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010315 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010316 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010317static void
10318xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010319 const xmlChar *q;
10320 xmlChar *ret = NULL;
10321
10322 if (CUR == '"') {
10323 NEXT;
10324 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010325 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010326 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010327 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010328 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10329 } else {
10330 ret = xmlStrndup(q, CUR_PTR - q);
10331 NEXT;
10332 }
10333 } else if (CUR == '\'') {
10334 NEXT;
10335 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010336 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010337 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010338 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010339 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10340 } else {
10341 ret = xmlStrndup(q, CUR_PTR - q);
10342 NEXT;
10343 }
10344 } else {
10345 XP_ERROR(XPATH_START_LITERAL_ERROR);
10346 }
10347 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010348 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010349 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010350 xmlFree(ret);
10351}
10352
10353/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010354 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010355 * @ctxt: the XPath Parser context
10356 *
10357 * Parse a VariableReference, evaluate it and push it on the stack.
10358 *
10359 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010360 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010361 * of any of the types that are possible for the value of an expression,
10362 * and may also be of additional types not specified here.
10363 *
10364 * Early evaluation is possible since:
10365 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010366 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010367 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010368 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010369 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010370static void
10371xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010372 xmlChar *name;
10373 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010374
10375 SKIP_BLANKS;
10376 if (CUR != '$') {
10377 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10378 }
10379 NEXT;
10380 name = xmlXPathParseQName(ctxt, &prefix);
10381 if (name == NULL) {
10382 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10383 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010384 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010385 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10386 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010387 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010388 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
Daniel Veillard47881282012-09-07 14:24:50 +080010389 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
Daniel Veillardb3d14912005-09-04 20:47:39 +000010390 }
Owen Taylor3473f882001-02-23 17:55:21 +000010391}
10392
10393/**
10394 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010395 * @name: a name string
10396 *
10397 * Is the name given a NodeType one.
10398 *
10399 * [38] NodeType ::= 'comment'
10400 * | 'text'
10401 * | 'processing-instruction'
10402 * | 'node'
10403 *
10404 * Returns 1 if true 0 otherwise
10405 */
10406int
10407xmlXPathIsNodeType(const xmlChar *name) {
10408 if (name == NULL)
10409 return(0);
10410
Daniel Veillard1971ee22002-01-31 20:29:19 +000010411 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010412 return(1);
10413 if (xmlStrEqual(name, BAD_CAST "text"))
10414 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010415 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010416 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010417 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010418 return(1);
10419 return(0);
10420}
10421
10422/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010423 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010424 * @ctxt: the XPath Parser context
10425 *
10426 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010427 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010428 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010429 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010430 * pushed on the stack
10431 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010432static void
10433xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010434 xmlChar *name;
10435 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010436 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010437 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010438
10439 name = xmlXPathParseQName(ctxt, &prefix);
10440 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010441 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010442 XP_ERROR(XPATH_EXPR_ERROR);
10443 }
10444 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010445#ifdef DEBUG_EXPR
10446 if (prefix == NULL)
10447 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10448 name);
10449 else
10450 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10451 prefix, name);
10452#endif
10453
Owen Taylor3473f882001-02-23 17:55:21 +000010454 if (CUR != '(') {
10455 XP_ERROR(XPATH_EXPR_ERROR);
10456 }
10457 NEXT;
10458 SKIP_BLANKS;
10459
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010460 /*
10461 * Optimization for count(): we don't need the node-set to be sorted.
10462 */
10463 if ((prefix == NULL) && (name[0] == 'c') &&
10464 xmlStrEqual(name, BAD_CAST "count"))
10465 {
10466 sort = 0;
10467 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010468 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010469 if (CUR != ')') {
10470 while (CUR != 0) {
10471 int op1 = ctxt->comp->last;
10472 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010473 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010474 if (ctxt->error != XPATH_EXPRESSION_OK) {
10475 xmlFree(name);
10476 xmlFree(prefix);
10477 return;
10478 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010479 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10480 nbargs++;
10481 if (CUR == ')') break;
10482 if (CUR != ',') {
10483 XP_ERROR(XPATH_EXPR_ERROR);
10484 }
10485 NEXT;
10486 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010487 }
Owen Taylor3473f882001-02-23 17:55:21 +000010488 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010489 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10490 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010491 NEXT;
10492 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010493}
10494
10495/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010496 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010497 * @ctxt: the XPath Parser context
10498 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010499 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010500 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010501 * | Literal
10502 * | Number
10503 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010504 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010505 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010506 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010507static void
10508xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010509 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010510 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010511 else if (CUR == '(') {
10512 NEXT;
10513 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010514 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010515 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010516 if (CUR != ')') {
10517 XP_ERROR(XPATH_EXPR_ERROR);
10518 }
10519 NEXT;
10520 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010521 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010522 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010523 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010524 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010525 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010526 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010527 }
10528 SKIP_BLANKS;
10529}
10530
10531/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010532 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010533 * @ctxt: the XPath Parser context
10534 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010535 * [20] FilterExpr ::= PrimaryExpr
10536 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010537 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010538 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010539 * Square brackets are used to filter expressions in the same way that
10540 * they are used in location paths. It is an error if the expression to
10541 * be filtered does not evaluate to a node-set. The context node list
10542 * used for evaluating the expression in square brackets is the node-set
10543 * to be filtered listed in document order.
10544 */
10545
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010546static void
10547xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10548 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010549 CHECK_ERROR;
10550 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010551
Owen Taylor3473f882001-02-23 17:55:21 +000010552 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010553 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010554 SKIP_BLANKS;
10555 }
10556
Daniel Veillard45490ae2008-07-29 09:13:19 +000010557
Owen Taylor3473f882001-02-23 17:55:21 +000010558}
10559
10560/**
10561 * xmlXPathScanName:
10562 * @ctxt: the XPath Parser context
10563 *
10564 * Trickery: parse an XML name but without consuming the input flow
10565 * Needed to avoid insanity in the parser state.
10566 *
10567 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10568 * CombiningChar | Extender
10569 *
10570 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10571 *
10572 * [6] Names ::= Name (S Name)*
10573 *
10574 * Returns the Name parsed or NULL
10575 */
10576
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010577static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010578xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010579 int len = 0, l;
10580 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010581 const xmlChar *cur;
10582 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010583
Daniel Veillard03226812004-11-01 14:55:21 +000010584 cur = ctxt->cur;
10585
10586 c = CUR_CHAR(l);
10587 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10588 (!IS_LETTER(c) && (c != '_') &&
10589 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010590 return(NULL);
10591 }
10592
Daniel Veillard03226812004-11-01 14:55:21 +000010593 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10594 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10595 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010596 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010597 (IS_COMBINING(c)) ||
10598 (IS_EXTENDER(c)))) {
10599 len += l;
10600 NEXTL(l);
10601 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010602 }
Daniel Veillard03226812004-11-01 14:55:21 +000010603 ret = xmlStrndup(cur, ctxt->cur - cur);
10604 ctxt->cur = cur;
10605 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010606}
10607
10608/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010609 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010610 * @ctxt: the XPath Parser context
10611 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010612 * [19] PathExpr ::= LocationPath
10613 * | FilterExpr
10614 * | FilterExpr '/' RelativeLocationPath
10615 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010616 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010617 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010618 * The / operator and // operators combine an arbitrary expression
10619 * and a relative location path. It is an error if the expression
10620 * does not evaluate to a node-set.
10621 * The / operator does composition in the same way as when / is
10622 * used in a location path. As in location paths, // is short for
10623 * /descendant-or-self::node()/.
10624 */
10625
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010626static void
10627xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010628 int lc = 1; /* Should we branch to LocationPath ? */
10629 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10630
10631 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010632 if ((CUR == '$') || (CUR == '(') ||
10633 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010634 (CUR == '\'') || (CUR == '"') ||
10635 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010636 lc = 0;
10637 } else if (CUR == '*') {
10638 /* relative or absolute location path */
10639 lc = 1;
10640 } else if (CUR == '/') {
10641 /* relative or absolute location path */
10642 lc = 1;
10643 } else if (CUR == '@') {
10644 /* relative abbreviated attribute location path */
10645 lc = 1;
10646 } else if (CUR == '.') {
10647 /* relative abbreviated attribute location path */
10648 lc = 1;
10649 } else {
10650 /*
10651 * Problem is finding if we have a name here whether it's:
10652 * - a nodetype
10653 * - a function call in which case it's followed by '('
10654 * - an axis in which case it's followed by ':'
10655 * - a element name
10656 * We do an a priori analysis here rather than having to
10657 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010658 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010659 * read/write/debug.
10660 */
10661 SKIP_BLANKS;
10662 name = xmlXPathScanName(ctxt);
10663 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10664#ifdef DEBUG_STEP
10665 xmlGenericError(xmlGenericErrorContext,
10666 "PathExpr: Axis\n");
10667#endif
10668 lc = 1;
10669 xmlFree(name);
10670 } else if (name != NULL) {
10671 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010672
Daniel Veillard45490ae2008-07-29 09:13:19 +000010673
Owen Taylor3473f882001-02-23 17:55:21 +000010674 while (NXT(len) != 0) {
10675 if (NXT(len) == '/') {
10676 /* element name */
10677#ifdef DEBUG_STEP
10678 xmlGenericError(xmlGenericErrorContext,
10679 "PathExpr: AbbrRelLocation\n");
10680#endif
10681 lc = 1;
10682 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010683 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010684 /* ignore blanks */
10685 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010686 } else if (NXT(len) == ':') {
10687#ifdef DEBUG_STEP
10688 xmlGenericError(xmlGenericErrorContext,
10689 "PathExpr: AbbrRelLocation\n");
10690#endif
10691 lc = 1;
10692 break;
10693 } else if ((NXT(len) == '(')) {
Brian C. Young142c7c62017-04-03 12:46:02 -070010694 /* Node Type or Function */
Owen Taylor3473f882001-02-23 17:55:21 +000010695 if (xmlXPathIsNodeType(name)) {
10696#ifdef DEBUG_STEP
10697 xmlGenericError(xmlGenericErrorContext,
10698 "PathExpr: Type search\n");
10699#endif
10700 lc = 1;
Brian C. Young142c7c62017-04-03 12:46:02 -070010701#ifdef LIBXML_XPTR_ENABLED
10702 } else if (ctxt->xptr &&
10703 xmlStrEqual(name, BAD_CAST "range-to")) {
10704 lc = 1;
10705#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010706 } else {
10707#ifdef DEBUG_STEP
10708 xmlGenericError(xmlGenericErrorContext,
10709 "PathExpr: function call\n");
10710#endif
10711 lc = 0;
10712 }
10713 break;
10714 } else if ((NXT(len) == '[')) {
10715 /* element name */
10716#ifdef DEBUG_STEP
10717 xmlGenericError(xmlGenericErrorContext,
10718 "PathExpr: AbbrRelLocation\n");
10719#endif
10720 lc = 1;
10721 break;
10722 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10723 (NXT(len) == '=')) {
10724 lc = 1;
10725 break;
10726 } else {
10727 lc = 1;
10728 break;
10729 }
10730 len++;
10731 }
10732 if (NXT(len) == 0) {
10733#ifdef DEBUG_STEP
10734 xmlGenericError(xmlGenericErrorContext,
10735 "PathExpr: AbbrRelLocation\n");
10736#endif
10737 /* element name */
10738 lc = 1;
10739 }
10740 xmlFree(name);
10741 } else {
William M. Brack08171912003-12-29 02:52:11 +000010742 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010743 XP_ERROR(XPATH_EXPR_ERROR);
10744 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010745 }
Owen Taylor3473f882001-02-23 17:55:21 +000010746
10747 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010748 if (CUR == '/') {
10749 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10750 } else {
10751 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010752 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010753 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010754 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010755 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010756 CHECK_ERROR;
10757 if ((CUR == '/') && (NXT(1) == '/')) {
10758 SKIP(2);
10759 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010760
10761 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10762 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10763 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10764
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010765 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010766 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010767 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010768 }
10769 }
10770 SKIP_BLANKS;
10771}
10772
10773/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010774 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010775 * @ctxt: the XPath Parser context
10776 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010777 * [18] UnionExpr ::= PathExpr
10778 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010779 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010780 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010781 */
10782
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010783static void
10784xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10785 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010786 CHECK_ERROR;
10787 SKIP_BLANKS;
10788 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010789 int op1 = ctxt->comp->last;
10790 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010791
10792 NEXT;
10793 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010794 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010795
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010796 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10797
Owen Taylor3473f882001-02-23 17:55:21 +000010798 SKIP_BLANKS;
10799 }
Owen Taylor3473f882001-02-23 17:55:21 +000010800}
10801
10802/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010803 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010804 * @ctxt: the XPath Parser context
10805 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010806 * [27] UnaryExpr ::= UnionExpr
10807 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010808 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010809 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010810 */
10811
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010812static void
10813xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010814 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010815 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010816
10817 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010818 while (CUR == '-') {
10819 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010820 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010821 NEXT;
10822 SKIP_BLANKS;
10823 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010824
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010825 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010826 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010827 if (found) {
10828 if (minus)
10829 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10830 else
10831 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010832 }
10833}
10834
10835/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010836 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010837 * @ctxt: the XPath Parser context
10838 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010839 * [26] MultiplicativeExpr ::= UnaryExpr
10840 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10841 * | MultiplicativeExpr 'div' UnaryExpr
10842 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010843 * [34] MultiplyOperator ::= '*'
10844 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010845 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010846 */
10847
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010848static void
10849xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10850 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010851 CHECK_ERROR;
10852 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010853 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010854 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10855 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10856 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010857 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010858
10859 if (CUR == '*') {
10860 op = 0;
10861 NEXT;
10862 } else if (CUR == 'd') {
10863 op = 1;
10864 SKIP(3);
10865 } else if (CUR == 'm') {
10866 op = 2;
10867 SKIP(3);
10868 }
10869 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010870 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010871 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010872 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010873 SKIP_BLANKS;
10874 }
10875}
10876
10877/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010878 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010879 * @ctxt: the XPath Parser context
10880 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010881 * [25] AdditiveExpr ::= MultiplicativeExpr
10882 * | AdditiveExpr '+' MultiplicativeExpr
10883 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010884 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010885 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010886 */
10887
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010888static void
10889xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010890
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010891 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010892 CHECK_ERROR;
10893 SKIP_BLANKS;
10894 while ((CUR == '+') || (CUR == '-')) {
10895 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010896 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010897
10898 if (CUR == '+') plus = 1;
10899 else plus = 0;
10900 NEXT;
10901 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010902 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010903 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010904 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010905 SKIP_BLANKS;
10906 }
10907}
10908
10909/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010910 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010911 * @ctxt: the XPath Parser context
10912 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010913 * [24] RelationalExpr ::= AdditiveExpr
10914 * | RelationalExpr '<' AdditiveExpr
10915 * | RelationalExpr '>' AdditiveExpr
10916 * | RelationalExpr '<=' AdditiveExpr
10917 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010918 *
10919 * A <= B > C is allowed ? Answer from James, yes with
10920 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10921 * which is basically what got implemented.
10922 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010923 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010924 * on the stack
10925 */
10926
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010927static void
10928xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10929 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010930 CHECK_ERROR;
10931 SKIP_BLANKS;
10932 while ((CUR == '<') ||
10933 (CUR == '>') ||
10934 ((CUR == '<') && (NXT(1) == '=')) ||
10935 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010936 int inf, strict;
10937 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010938
10939 if (CUR == '<') inf = 1;
10940 else inf = 0;
10941 if (NXT(1) == '=') strict = 0;
10942 else strict = 1;
10943 NEXT;
10944 if (!strict) NEXT;
10945 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010946 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010947 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010948 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010949 SKIP_BLANKS;
10950 }
10951}
10952
10953/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010954 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010955 * @ctxt: the XPath Parser context
10956 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010957 * [23] EqualityExpr ::= RelationalExpr
10958 * | EqualityExpr '=' RelationalExpr
10959 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010960 *
10961 * A != B != C is allowed ? Answer from James, yes with
10962 * (RelationalExpr = RelationalExpr) = RelationalExpr
10963 * (RelationalExpr != RelationalExpr) != RelationalExpr
10964 * which is basically what got implemented.
10965 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010966 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010967 *
10968 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010969static void
10970xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10971 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010972 CHECK_ERROR;
10973 SKIP_BLANKS;
10974 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010975 int eq;
10976 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010977
10978 if (CUR == '=') eq = 1;
10979 else eq = 0;
10980 NEXT;
10981 if (!eq) NEXT;
10982 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010983 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010984 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010985 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010986 SKIP_BLANKS;
10987 }
10988}
10989
10990/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010991 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010992 * @ctxt: the XPath Parser context
10993 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010994 * [22] AndExpr ::= EqualityExpr
10995 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010996 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010997 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010998 *
10999 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011000static void
11001xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11002 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011003 CHECK_ERROR;
11004 SKIP_BLANKS;
11005 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011006 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011007 SKIP(3);
11008 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011009 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011010 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011011 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011012 SKIP_BLANKS;
11013 }
11014}
11015
11016/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000011017 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000011018 * @ctxt: the XPath Parser context
11019 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011020 * [14] Expr ::= OrExpr
11021 * [21] OrExpr ::= AndExpr
11022 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000011023 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011024 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000011025 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011026static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011027xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011028 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011029 CHECK_ERROR;
11030 SKIP_BLANKS;
11031 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011032 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011033 SKIP(2);
11034 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011035 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011036 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011037 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011038 SKIP_BLANKS;
11039 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011040 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011041 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011042 /*
11043 * This is the main place to eliminate sorting for
11044 * operations which don't require a sorted node-set.
11045 * E.g. count().
11046 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011047 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11048 }
Owen Taylor3473f882001-02-23 17:55:21 +000011049}
11050
11051/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011052 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000011053 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011054 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000011055 *
11056 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000011057 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000011058 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011059 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000011060 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011061static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011062xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011063 int op1 = ctxt->comp->last;
11064
11065 SKIP_BLANKS;
11066 if (CUR != '[') {
11067 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11068 }
11069 NEXT;
11070 SKIP_BLANKS;
11071
11072 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011073 /*
11074 * This call to xmlXPathCompileExpr() will deactivate sorting
11075 * of the predicate result.
11076 * TODO: Sorting is still activated for filters, since I'm not
11077 * sure if needed. Normally sorting should not be needed, since
11078 * a filter can only diminish the number of items in a sequence,
11079 * but won't change its order; so if the initial sequence is sorted,
11080 * subsequent sorting is not needed.
11081 */
11082 if (! filter)
11083 xmlXPathCompileExpr(ctxt, 0);
11084 else
11085 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011086 CHECK_ERROR;
11087
11088 if (CUR != ']') {
11089 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11090 }
11091
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011092 if (filter)
11093 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11094 else
11095 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011096
11097 NEXT;
11098 SKIP_BLANKS;
11099}
11100
11101/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011102 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011103 * @ctxt: the XPath Parser context
11104 * @test: pointer to a xmlXPathTestVal
11105 * @type: pointer to a xmlXPathTypeVal
11106 * @prefix: placeholder for a possible name prefix
11107 *
11108 * [7] NodeTest ::= NameTest
11109 * | NodeType '(' ')'
11110 * | 'processing-instruction' '(' Literal ')'
11111 *
11112 * [37] NameTest ::= '*'
11113 * | NCName ':' '*'
11114 * | QName
11115 * [38] NodeType ::= 'comment'
11116 * | 'text'
11117 * | 'processing-instruction'
11118 * | 'node'
11119 *
William M. Brack08171912003-12-29 02:52:11 +000011120 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011121 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011122static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011123xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11124 xmlXPathTypeVal *type, const xmlChar **prefix,
11125 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011126 int blanks;
11127
11128 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11129 STRANGE;
11130 return(NULL);
11131 }
William M. Brack78637da2003-07-31 14:47:38 +000011132 *type = (xmlXPathTypeVal) 0;
11133 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011134 *prefix = NULL;
11135 SKIP_BLANKS;
11136
11137 if ((name == NULL) && (CUR == '*')) {
11138 /*
11139 * All elements
11140 */
11141 NEXT;
11142 *test = NODE_TEST_ALL;
11143 return(NULL);
11144 }
11145
11146 if (name == NULL)
11147 name = xmlXPathParseNCName(ctxt);
11148 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011149 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011150 }
11151
William M. Brack76e95df2003-10-18 16:20:14 +000011152 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011153 SKIP_BLANKS;
11154 if (CUR == '(') {
11155 NEXT;
11156 /*
11157 * NodeType or PI search
11158 */
11159 if (xmlStrEqual(name, BAD_CAST "comment"))
11160 *type = NODE_TYPE_COMMENT;
11161 else if (xmlStrEqual(name, BAD_CAST "node"))
11162 *type = NODE_TYPE_NODE;
11163 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11164 *type = NODE_TYPE_PI;
11165 else if (xmlStrEqual(name, BAD_CAST "text"))
11166 *type = NODE_TYPE_TEXT;
11167 else {
11168 if (name != NULL)
11169 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011170 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011171 }
11172
11173 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011174
Owen Taylor3473f882001-02-23 17:55:21 +000011175 SKIP_BLANKS;
11176 if (*type == NODE_TYPE_PI) {
11177 /*
11178 * Specific case: search a PI by name.
11179 */
Owen Taylor3473f882001-02-23 17:55:21 +000011180 if (name != NULL)
11181 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011182 name = NULL;
11183 if (CUR != ')') {
11184 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011185 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011186 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011187 SKIP_BLANKS;
11188 }
Owen Taylor3473f882001-02-23 17:55:21 +000011189 }
11190 if (CUR != ')') {
11191 if (name != NULL)
11192 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011193 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011194 }
11195 NEXT;
11196 return(name);
11197 }
11198 *test = NODE_TEST_NAME;
11199 if ((!blanks) && (CUR == ':')) {
11200 NEXT;
11201
11202 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011203 * Since currently the parser context don't have a
11204 * namespace list associated:
11205 * The namespace name for this prefix can be computed
11206 * only at evaluation time. The compilation is done
11207 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011208 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011209#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011210 *prefix = xmlXPathNsLookup(ctxt->context, name);
11211 if (name != NULL)
11212 xmlFree(name);
11213 if (*prefix == NULL) {
11214 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11215 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011216#else
11217 *prefix = name;
11218#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011219
11220 if (CUR == '*') {
11221 /*
11222 * All elements
11223 */
11224 NEXT;
11225 *test = NODE_TEST_ALL;
11226 return(NULL);
11227 }
11228
11229 name = xmlXPathParseNCName(ctxt);
11230 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011231 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011232 }
11233 }
11234 return(name);
11235}
11236
11237/**
11238 * xmlXPathIsAxisName:
11239 * @name: a preparsed name token
11240 *
11241 * [6] AxisName ::= 'ancestor'
11242 * | 'ancestor-or-self'
11243 * | 'attribute'
11244 * | 'child'
11245 * | 'descendant'
11246 * | 'descendant-or-self'
11247 * | 'following'
11248 * | 'following-sibling'
11249 * | 'namespace'
11250 * | 'parent'
11251 * | 'preceding'
11252 * | 'preceding-sibling'
11253 * | 'self'
11254 *
11255 * Returns the axis or 0
11256 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011257static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011258xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011259 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011260 switch (name[0]) {
11261 case 'a':
11262 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11263 ret = AXIS_ANCESTOR;
11264 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11265 ret = AXIS_ANCESTOR_OR_SELF;
11266 if (xmlStrEqual(name, BAD_CAST "attribute"))
11267 ret = AXIS_ATTRIBUTE;
11268 break;
11269 case 'c':
11270 if (xmlStrEqual(name, BAD_CAST "child"))
11271 ret = AXIS_CHILD;
11272 break;
11273 case 'd':
11274 if (xmlStrEqual(name, BAD_CAST "descendant"))
11275 ret = AXIS_DESCENDANT;
11276 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11277 ret = AXIS_DESCENDANT_OR_SELF;
11278 break;
11279 case 'f':
11280 if (xmlStrEqual(name, BAD_CAST "following"))
11281 ret = AXIS_FOLLOWING;
11282 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11283 ret = AXIS_FOLLOWING_SIBLING;
11284 break;
11285 case 'n':
11286 if (xmlStrEqual(name, BAD_CAST "namespace"))
11287 ret = AXIS_NAMESPACE;
11288 break;
11289 case 'p':
11290 if (xmlStrEqual(name, BAD_CAST "parent"))
11291 ret = AXIS_PARENT;
11292 if (xmlStrEqual(name, BAD_CAST "preceding"))
11293 ret = AXIS_PRECEDING;
11294 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11295 ret = AXIS_PRECEDING_SIBLING;
11296 break;
11297 case 's':
11298 if (xmlStrEqual(name, BAD_CAST "self"))
11299 ret = AXIS_SELF;
11300 break;
11301 }
11302 return(ret);
11303}
11304
11305/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011306 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011307 * @ctxt: the XPath Parser context
11308 *
11309 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011310 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011311 *
11312 * [12] AbbreviatedStep ::= '.' | '..'
11313 *
11314 * [5] AxisSpecifier ::= AxisName '::'
11315 * | AbbreviatedAxisSpecifier
11316 *
11317 * [13] AbbreviatedAxisSpecifier ::= '@'?
11318 *
11319 * Modified for XPtr range support as:
11320 *
11321 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11322 * | AbbreviatedStep
11323 * | 'range-to' '(' Expr ')' Predicate*
11324 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011325 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011326 * A location step of . is short for self::node(). This is
11327 * particularly useful in conjunction with //. For example, the
11328 * location path .//para is short for
11329 * self::node()/descendant-or-self::node()/child::para
11330 * and so will select all para descendant elements of the context
11331 * node.
11332 * Similarly, a location step of .. is short for parent::node().
11333 * For example, ../title is short for parent::node()/child::title
11334 * and so will select the title children of the parent of the context
11335 * node.
11336 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011337static void
11338xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011339#ifdef LIBXML_XPTR_ENABLED
11340 int rangeto = 0;
11341 int op2 = -1;
11342#endif
11343
Owen Taylor3473f882001-02-23 17:55:21 +000011344 SKIP_BLANKS;
11345 if ((CUR == '.') && (NXT(1) == '.')) {
11346 SKIP(2);
11347 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011348 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11349 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011350 } else if (CUR == '.') {
11351 NEXT;
11352 SKIP_BLANKS;
11353 } else {
11354 xmlChar *name = NULL;
11355 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011356 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011357 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011358 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011359 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011360
11361 /*
11362 * The modification needed for XPointer change to the production
11363 */
11364#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011365 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011366 name = xmlXPathParseNCName(ctxt);
11367 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011368 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011369 xmlFree(name);
11370 SKIP_BLANKS;
11371 if (CUR != '(') {
11372 XP_ERROR(XPATH_EXPR_ERROR);
11373 }
11374 NEXT;
11375 SKIP_BLANKS;
11376
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011377 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011378 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011379 CHECK_ERROR;
11380
11381 SKIP_BLANKS;
11382 if (CUR != ')') {
11383 XP_ERROR(XPATH_EXPR_ERROR);
11384 }
11385 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011386 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011387 goto eval_predicates;
11388 }
11389 }
11390#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011391 if (CUR == '*') {
11392 axis = AXIS_CHILD;
11393 } else {
11394 if (name == NULL)
11395 name = xmlXPathParseNCName(ctxt);
11396 if (name != NULL) {
11397 axis = xmlXPathIsAxisName(name);
11398 if (axis != 0) {
11399 SKIP_BLANKS;
11400 if ((CUR == ':') && (NXT(1) == ':')) {
11401 SKIP(2);
11402 xmlFree(name);
11403 name = NULL;
11404 } else {
11405 /* an element name can conflict with an axis one :-\ */
11406 axis = AXIS_CHILD;
11407 }
Owen Taylor3473f882001-02-23 17:55:21 +000011408 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011409 axis = AXIS_CHILD;
11410 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011411 } else if (CUR == '@') {
11412 NEXT;
11413 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011414 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011415 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011416 }
Owen Taylor3473f882001-02-23 17:55:21 +000011417 }
11418
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011419 if (ctxt->error != XPATH_EXPRESSION_OK) {
11420 xmlFree(name);
11421 return;
11422 }
Owen Taylor3473f882001-02-23 17:55:21 +000011423
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011424 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011425 if (test == 0)
11426 return;
11427
Daniel Veillarded6c5492005-07-23 15:00:22 +000011428 if ((prefix != NULL) && (ctxt->context != NULL) &&
11429 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11430 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11431 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11432 }
11433 }
Owen Taylor3473f882001-02-23 17:55:21 +000011434#ifdef DEBUG_STEP
11435 xmlGenericError(xmlGenericErrorContext,
11436 "Basis : computing new set\n");
11437#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011438
Owen Taylor3473f882001-02-23 17:55:21 +000011439#ifdef DEBUG_STEP
11440 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011441 if (ctxt->value == NULL)
11442 xmlGenericError(xmlGenericErrorContext, "no value\n");
11443 else if (ctxt->value->nodesetval == NULL)
11444 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11445 else
11446 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011447#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011448
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011449#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011450eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011451#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011452 op1 = ctxt->comp->last;
11453 ctxt->comp->last = -1;
11454
Owen Taylor3473f882001-02-23 17:55:21 +000011455 SKIP_BLANKS;
11456 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011457 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011458 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011459
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011460#ifdef LIBXML_XPTR_ENABLED
11461 if (rangeto) {
11462 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11463 } else
11464#endif
11465 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11466 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011467
Owen Taylor3473f882001-02-23 17:55:21 +000011468 }
11469#ifdef DEBUG_STEP
11470 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011471 if (ctxt->value == NULL)
11472 xmlGenericError(xmlGenericErrorContext, "no value\n");
11473 else if (ctxt->value->nodesetval == NULL)
11474 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11475 else
11476 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11477 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011478#endif
11479}
11480
11481/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011482 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011483 * @ctxt: the XPath Parser context
11484 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011485 * [3] RelativeLocationPath ::= Step
11486 * | RelativeLocationPath '/' Step
11487 * | AbbreviatedRelativeLocationPath
11488 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011489 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011490 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011491 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011492static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011493xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011494(xmlXPathParserContextPtr ctxt) {
11495 SKIP_BLANKS;
11496 if ((CUR == '/') && (NXT(1) == '/')) {
11497 SKIP(2);
11498 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011499 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11500 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011501 } else if (CUR == '/') {
11502 NEXT;
11503 SKIP_BLANKS;
11504 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011505 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011506 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011507 SKIP_BLANKS;
11508 while (CUR == '/') {
11509 if ((CUR == '/') && (NXT(1) == '/')) {
11510 SKIP(2);
11511 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011512 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011513 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011514 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011515 } else if (CUR == '/') {
11516 NEXT;
11517 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011518 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011519 }
11520 SKIP_BLANKS;
11521 }
11522}
11523
11524/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011525 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011526 * @ctxt: the XPath Parser context
11527 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011528 * [1] LocationPath ::= RelativeLocationPath
11529 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011530 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011531 * | AbbreviatedAbsoluteLocationPath
11532 * [10] AbbreviatedAbsoluteLocationPath ::=
11533 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011534 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011535 * Compile a location path
11536 *
Owen Taylor3473f882001-02-23 17:55:21 +000011537 * // is short for /descendant-or-self::node()/. For example,
11538 * //para is short for /descendant-or-self::node()/child::para and
11539 * so will select any para element in the document (even a para element
11540 * that is a document element will be selected by //para since the
11541 * document element node is a child of the root node); div//para is
11542 * short for div/descendant-or-self::node()/child::para and so will
11543 * select all para descendants of div children.
11544 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011545static void
11546xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011547 SKIP_BLANKS;
11548 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011549 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011550 } else {
11551 while (CUR == '/') {
11552 if ((CUR == '/') && (NXT(1) == '/')) {
11553 SKIP(2);
11554 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011555 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11556 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011557 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011558 } else if (CUR == '/') {
11559 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011560 SKIP_BLANKS;
11561 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011562 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011563 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011564 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011565 }
Martin729601f2009-10-12 22:42:26 +020011566 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011567 }
11568 }
11569}
11570
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011571/************************************************************************
11572 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011573 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011574 * *
11575 ************************************************************************/
11576
Daniel Veillardf06307e2001-07-03 10:35:50 +000011577static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011578xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11579
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011580#ifdef DEBUG_STEP
11581static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011582xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011583 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011584{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011585 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011586 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011587 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011588 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011589 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011590 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011591 xmlGenericError(xmlGenericErrorContext,
11592 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011593 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011594 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011595 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011596 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011597 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011598 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011599 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011600 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011601 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011602 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011603 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011604 xmlGenericError(xmlGenericErrorContext,
11605 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011606 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011607 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011608 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011609 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011610 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011611 xmlGenericError(xmlGenericErrorContext,
11612 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011613 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011614 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011615 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011616 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011617 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011618 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011619 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011620 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011621 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011622 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011623 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011624 xmlGenericError(xmlGenericErrorContext,
11625 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011626 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011627 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011628 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011629 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011630 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011631 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011632 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011633 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011634 case NODE_TEST_NONE:
11635 xmlGenericError(xmlGenericErrorContext,
11636 " searching for none !!!\n");
11637 break;
11638 case NODE_TEST_TYPE:
11639 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011640 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011641 break;
11642 case NODE_TEST_PI:
11643 xmlGenericError(xmlGenericErrorContext,
11644 " searching for PI !!!\n");
11645 break;
11646 case NODE_TEST_ALL:
11647 xmlGenericError(xmlGenericErrorContext,
11648 " searching for *\n");
11649 break;
11650 case NODE_TEST_NS:
11651 xmlGenericError(xmlGenericErrorContext,
11652 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011653 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011654 break;
11655 case NODE_TEST_NAME:
11656 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011657 " searching for name %s\n", op->value5);
11658 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011659 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011660 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011661 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011662 }
11663 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011664}
11665#endif /* DEBUG_STEP */
11666
11667static int
11668xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11669 xmlXPathStepOpPtr op,
11670 xmlNodeSetPtr set,
11671 int contextSize,
11672 int hasNsNodes)
11673{
11674 if (op->ch1 != -1) {
11675 xmlXPathCompExprPtr comp = ctxt->comp;
11676 /*
11677 * Process inner predicates first.
11678 */
11679 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11680 /*
11681 * TODO: raise an internal error.
11682 */
11683 }
11684 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11685 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11686 CHECK_ERROR0;
11687 if (contextSize <= 0)
11688 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011689 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011690 if (op->ch2 != -1) {
11691 xmlXPathContextPtr xpctxt = ctxt->context;
11692 xmlNodePtr contextNode, oldContextNode;
11693 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011694 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011695 xmlXPathStepOpPtr exprOp;
11696 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11697
11698#ifdef LIBXML_XPTR_ENABLED
11699 /*
11700 * URGENT TODO: Check the following:
11701 * We don't expect location sets if evaluating prediates, right?
11702 * Only filters should expect location sets, right?
11703 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011704#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011705 /*
11706 * SPEC XPath 1.0:
11707 * "For each node in the node-set to be filtered, the
11708 * PredicateExpr is evaluated with that node as the
11709 * context node, with the number of nodes in the
11710 * node-set as the context size, and with the proximity
11711 * position of the node in the node-set with respect to
11712 * the axis as the context position;"
11713 * @oldset is the node-set" to be filtered.
11714 *
11715 * SPEC XPath 1.0:
11716 * "only predicates change the context position and
11717 * context size (see [2.4 Predicates])."
11718 * Example:
11719 * node-set context pos
11720 * nA 1
11721 * nB 2
11722 * nC 3
11723 * After applying predicate [position() > 1] :
11724 * node-set context pos
11725 * nB 1
11726 * nC 2
11727 */
11728 oldContextNode = xpctxt->node;
11729 oldContextDoc = xpctxt->doc;
11730 /*
11731 * Get the expression of this predicate.
11732 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011733 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011734 newContextSize = 0;
11735 for (i = 0; i < set->nodeNr; i++) {
11736 if (set->nodeTab[i] == NULL)
11737 continue;
11738
11739 contextNode = set->nodeTab[i];
11740 xpctxt->node = contextNode;
11741 xpctxt->contextSize = contextSize;
11742 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011743
11744 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011745 * Also set the xpath document in case things like
11746 * key() are evaluated in the predicate.
11747 */
11748 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11749 (contextNode->doc != NULL))
11750 xpctxt->doc = contextNode->doc;
11751 /*
11752 * Evaluate the predicate expression with 1 context node
11753 * at a time; this node is packaged into a node set; this
11754 * node set is handed over to the evaluation mechanism.
11755 */
11756 if (contextObj == NULL)
11757 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011758 else {
11759 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11760 contextNode) < 0) {
11761 ctxt->error = XPATH_MEMORY_ERROR;
11762 goto evaluation_exit;
11763 }
11764 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011765
11766 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011767
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011768 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011769
William M. Brack0bcec062007-02-14 02:15:19 +000011770 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11771 xmlXPathNodeSetClear(set, hasNsNodes);
11772 newContextSize = 0;
11773 goto evaluation_exit;
11774 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011775
11776 if (res != 0) {
11777 newContextSize++;
11778 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011779 /*
11780 * Remove the entry from the initial node set.
11781 */
11782 set->nodeTab[i] = NULL;
11783 if (contextNode->type == XML_NAMESPACE_DECL)
11784 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011785 }
11786 if (ctxt->value == contextObj) {
11787 /*
11788 * Don't free the temporary XPath object holding the
11789 * context node, in order to avoid massive recreation
11790 * inside this loop.
11791 */
11792 valuePop(ctxt);
11793 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11794 } else {
11795 /*
11796 * TODO: The object was lost in the evaluation machinery.
11797 * Can this happen? Maybe in internal-error cases.
11798 */
11799 contextObj = NULL;
11800 }
11801 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011802
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011803 if (contextObj != NULL) {
11804 if (ctxt->value == contextObj)
11805 valuePop(ctxt);
11806 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011807 }
William M. Brack0bcec062007-02-14 02:15:19 +000011808evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011809 if (exprRes != NULL)
11810 xmlXPathReleaseObject(ctxt->context, exprRes);
11811 /*
11812 * Reset/invalidate the context.
11813 */
11814 xpctxt->node = oldContextNode;
11815 xpctxt->doc = oldContextDoc;
11816 xpctxt->contextSize = -1;
11817 xpctxt->proximityPosition = -1;
11818 return(newContextSize);
11819 }
11820 return(contextSize);
11821}
11822
11823static int
11824xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11825 xmlXPathStepOpPtr op,
11826 xmlNodeSetPtr set,
11827 int contextSize,
11828 int minPos,
11829 int maxPos,
11830 int hasNsNodes)
11831{
11832 if (op->ch1 != -1) {
11833 xmlXPathCompExprPtr comp = ctxt->comp;
11834 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11835 /*
11836 * TODO: raise an internal error.
11837 */
11838 }
11839 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11840 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11841 CHECK_ERROR0;
11842 if (contextSize <= 0)
11843 return(0);
11844 }
11845 /*
11846 * Check if the node set contains a sufficient number of nodes for
11847 * the requested range.
11848 */
11849 if (contextSize < minPos) {
11850 xmlXPathNodeSetClear(set, hasNsNodes);
11851 return(0);
11852 }
11853 if (op->ch2 == -1) {
11854 /*
11855 * TODO: Can this ever happen?
11856 */
11857 return (contextSize);
11858 } else {
11859 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011860 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011861 xmlXPathStepOpPtr exprOp;
11862 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11863 xmlNodePtr oldContextNode, contextNode = NULL;
11864 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011865 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011866
11867#ifdef LIBXML_XPTR_ENABLED
11868 /*
11869 * URGENT TODO: Check the following:
11870 * We don't expect location sets if evaluating prediates, right?
11871 * Only filters should expect location sets, right?
11872 */
11873#endif /* LIBXML_XPTR_ENABLED */
11874
11875 /*
11876 * Save old context.
11877 */
11878 oldContextNode = xpctxt->node;
11879 oldContextDoc = xpctxt->doc;
11880 /*
11881 * Get the expression of this predicate.
11882 */
11883 exprOp = &ctxt->comp->steps[op->ch2];
11884 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011885 xmlXPathObjectPtr tmp;
11886
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011887 if (set->nodeTab[i] == NULL)
11888 continue;
11889
11890 contextNode = set->nodeTab[i];
11891 xpctxt->node = contextNode;
11892 xpctxt->contextSize = contextSize;
11893 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011894
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011895 /*
11896 * Initialize the new set.
11897 * Also set the xpath document in case things like
11898 * key() evaluation are attempted on the predicate
11899 */
11900 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11901 (contextNode->doc != NULL))
11902 xpctxt->doc = contextNode->doc;
11903 /*
11904 * Evaluate the predicate expression with 1 context node
11905 * at a time; this node is packaged into a node set; this
11906 * node set is handed over to the evaluation mechanism.
11907 */
11908 if (contextObj == NULL)
11909 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011910 else {
11911 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11912 contextNode) < 0) {
11913 ctxt->error = XPATH_MEMORY_ERROR;
11914 goto evaluation_exit;
11915 }
11916 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011917
Daniel Veillardf5048b32011-08-18 17:10:13 +080011918 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011919 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011920 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011921 tmp = valuePop(ctxt);
11922 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011923
William M. Brackf1794562007-08-23 12:58:13 +000011924 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011925 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011926 /*
11927 * Free up the result
11928 * then pop off contextObj, which will be freed later
11929 */
11930 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011931 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011932 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011933 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011934 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011935 /* push the result back onto the stack */
11936 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011937
11938 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011939 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011940
11941 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011942 /*
11943 * Fits in the requested range.
11944 */
11945 newContextSize++;
11946 if (minPos == maxPos) {
11947 /*
11948 * Only 1 node was requested.
11949 */
11950 if (contextNode->type == XML_NAMESPACE_DECL) {
11951 /*
11952 * As always: take care of those nasty
11953 * namespace nodes.
11954 */
11955 set->nodeTab[i] = NULL;
11956 }
11957 xmlXPathNodeSetClear(set, hasNsNodes);
11958 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011959 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011960 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011961 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011962 if (pos == maxPos) {
11963 /*
11964 * We are done.
11965 */
11966 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11967 goto evaluation_exit;
11968 }
11969 } else {
11970 /*
11971 * Remove the entry from the initial node set.
11972 */
11973 set->nodeTab[i] = NULL;
11974 if (contextNode->type == XML_NAMESPACE_DECL)
11975 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11976 }
11977 if (exprRes != NULL) {
11978 xmlXPathReleaseObject(ctxt->context, exprRes);
11979 exprRes = NULL;
11980 }
11981 if (ctxt->value == contextObj) {
11982 /*
11983 * Don't free the temporary XPath object holding the
11984 * context node, in order to avoid massive recreation
11985 * inside this loop.
11986 */
11987 valuePop(ctxt);
11988 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11989 } else {
11990 /*
11991 * The object was lost in the evaluation machinery.
11992 * Can this happen? Maybe in case of internal-errors.
11993 */
11994 contextObj = NULL;
11995 }
11996 }
11997 goto evaluation_exit;
11998
11999evaluation_error:
12000 xmlXPathNodeSetClear(set, hasNsNodes);
12001 newContextSize = 0;
12002
12003evaluation_exit:
12004 if (contextObj != NULL) {
12005 if (ctxt->value == contextObj)
12006 valuePop(ctxt);
12007 xmlXPathReleaseObject(xpctxt, contextObj);
12008 }
12009 if (exprRes != NULL)
12010 xmlXPathReleaseObject(ctxt->context, exprRes);
12011 /*
12012 * Reset/invalidate the context.
12013 */
12014 xpctxt->node = oldContextNode;
12015 xpctxt->doc = oldContextDoc;
12016 xpctxt->contextSize = -1;
12017 xpctxt->proximityPosition = -1;
12018 return(newContextSize);
12019 }
12020 return(contextSize);
12021}
12022
12023static int
12024xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000012025 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012026 int *maxPos)
12027{
12028
12029 xmlXPathStepOpPtr exprOp;
12030
12031 /*
12032 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12033 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012034
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012035 /*
12036 * If not -1, then ch1 will point to:
12037 * 1) For predicates (XPATH_OP_PREDICATE):
12038 * - an inner predicate operator
12039 * 2) For filters (XPATH_OP_FILTER):
12040 * - an inner filter operater OR
12041 * - an expression selecting the node set.
12042 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012043 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012044 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12045 return(0);
12046
12047 if (op->ch2 != -1) {
12048 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012049 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012050 return(0);
12051
12052 if ((exprOp != NULL) &&
12053 (exprOp->op == XPATH_OP_VALUE) &&
12054 (exprOp->value4 != NULL) &&
12055 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12056 {
12057 /*
12058 * We have a "[n]" predicate here.
12059 * TODO: Unfortunately this simplistic test here is not
12060 * able to detect a position() predicate in compound
12061 * expressions like "[@attr = 'a" and position() = 1],
12062 * and even not the usage of position() in
12063 * "[position() = 1]"; thus - obviously - a position-range,
12064 * like it "[position() < 5]", is also not detected.
12065 * Maybe we could rewrite the AST to ease the optimization.
12066 */
12067 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012068
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012069 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12070 (float) *maxPos)
Daniel Veillard45490ae2008-07-29 09:13:19 +000012071 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012072 return(1);
12073 }
12074 }
12075 return(0);
12076}
12077
12078static int
12079xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12080 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012081 xmlNodePtr * first, xmlNodePtr * last,
12082 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012083{
12084
12085#define XP_TEST_HIT \
12086 if (hasAxisRange != 0) { \
12087 if (++pos == maxPos) { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012088 if (addNode(seq, cur) < 0) \
12089 ctxt->error = XPATH_MEMORY_ERROR; \
12090 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012091 } else { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012092 if (addNode(seq, cur) < 0) \
12093 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012094 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012095
12096#define XP_TEST_HIT_NS \
12097 if (hasAxisRange != 0) { \
12098 if (++pos == maxPos) { \
12099 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012100 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12101 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012102 goto axis_range_end; } \
12103 } else { \
12104 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012105 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12106 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012107 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012108
12109 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12110 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12111 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12112 const xmlChar *prefix = op->value4;
12113 const xmlChar *name = op->value5;
12114 const xmlChar *URI = NULL;
12115
12116#ifdef DEBUG_STEP
12117 int nbMatches = 0, prevMatches = 0;
12118#endif
12119 int total = 0, hasNsNodes = 0;
12120 /* The popped object holding the context nodes */
12121 xmlXPathObjectPtr obj;
12122 /* The set of context nodes for the node tests */
12123 xmlNodeSetPtr contextSeq;
12124 int contextIdx;
12125 xmlNodePtr contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012126 /* The final resulting node set wrt to all context nodes */
12127 xmlNodeSetPtr outSeq;
12128 /*
12129 * The temporary resulting node set wrt 1 context node.
12130 * Used to feed predicate evaluation.
12131 */
12132 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012133 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012134 /* First predicate operator */
12135 xmlXPathStepOpPtr predOp;
12136 int maxPos; /* The requested position() (when a "[n]" predicate) */
12137 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012138 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012139
12140 xmlXPathTraversalFunction next = NULL;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012141 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012142 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012143 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012144 xmlXPathContextPtr xpctxt = ctxt->context;
12145
12146
12147 CHECK_TYPE0(XPATH_NODESET);
12148 obj = valuePop(ctxt);
12149 /*
12150 * Setup namespaces.
12151 */
12152 if (prefix != NULL) {
12153 URI = xmlXPathNsLookup(xpctxt, prefix);
12154 if (URI == NULL) {
12155 xmlXPathReleaseObject(xpctxt, obj);
12156 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12157 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012158 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012159 /*
12160 * Setup axis.
12161 *
12162 * MAYBE FUTURE TODO: merging optimizations:
12163 * - If the nodes to be traversed wrt to the initial nodes and
12164 * the current axis cannot overlap, then we could avoid searching
12165 * for duplicates during the merge.
12166 * But the question is how/when to evaluate if they cannot overlap.
12167 * Example: if we know that for two initial nodes, the one is
12168 * not in the ancestor-or-self axis of the other, then we could safely
12169 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12170 * the descendant-or-self axis.
12171 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012172 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12173 switch (axis) {
12174 case AXIS_ANCESTOR:
12175 first = NULL;
12176 next = xmlXPathNextAncestor;
12177 break;
12178 case AXIS_ANCESTOR_OR_SELF:
12179 first = NULL;
12180 next = xmlXPathNextAncestorOrSelf;
12181 break;
12182 case AXIS_ATTRIBUTE:
12183 first = NULL;
12184 last = NULL;
12185 next = xmlXPathNextAttribute;
12186 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12187 break;
12188 case AXIS_CHILD:
12189 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012190 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12191 (type == NODE_TYPE_NODE))
12192 {
12193 /*
12194 * Optimization if an element node type is 'element'.
12195 */
12196 next = xmlXPathNextChildElement;
12197 } else
12198 next = xmlXPathNextChild;
12199 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12200 break;
12201 case AXIS_DESCENDANT:
12202 last = NULL;
12203 next = xmlXPathNextDescendant;
12204 break;
12205 case AXIS_DESCENDANT_OR_SELF:
12206 last = NULL;
12207 next = xmlXPathNextDescendantOrSelf;
12208 break;
12209 case AXIS_FOLLOWING:
12210 last = NULL;
12211 next = xmlXPathNextFollowing;
12212 break;
12213 case AXIS_FOLLOWING_SIBLING:
12214 last = NULL;
12215 next = xmlXPathNextFollowingSibling;
12216 break;
12217 case AXIS_NAMESPACE:
12218 first = NULL;
12219 last = NULL;
12220 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12221 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12222 break;
12223 case AXIS_PARENT:
12224 first = NULL;
12225 next = xmlXPathNextParent;
12226 break;
12227 case AXIS_PRECEDING:
12228 first = NULL;
12229 next = xmlXPathNextPrecedingInternal;
12230 break;
12231 case AXIS_PRECEDING_SIBLING:
12232 first = NULL;
12233 next = xmlXPathNextPrecedingSibling;
12234 break;
12235 case AXIS_SELF:
12236 first = NULL;
12237 last = NULL;
12238 next = xmlXPathNextSelf;
12239 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12240 break;
12241 }
12242
12243#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012244 xmlXPathDebugDumpStepAxis(op,
12245 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012246#endif
12247
12248 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012249 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012250 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012251 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012252 contextSeq = obj->nodesetval;
12253 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12254 xmlXPathReleaseObject(xpctxt, obj);
12255 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12256 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012257 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012258 /*
12259 * Predicate optimization ---------------------------------------------
12260 * If this step has a last predicate, which contains a position(),
12261 * then we'll optimize (although not exactly "position()", but only
12262 * the short-hand form, i.e., "[n]".
12263 *
12264 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012265 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012266 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12267 * ROOT -- op->ch1
12268 * PREDICATE -- op->ch2 (predOp)
12269 * PREDICATE -- predOp->ch1 = [parent::bar]
12270 * SORT
12271 * COLLECT 'parent' 'name' 'node' bar
12272 * NODE
12273 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12274 *
12275 */
12276 maxPos = 0;
12277 predOp = NULL;
12278 hasPredicateRange = 0;
12279 hasAxisRange = 0;
12280 if (op->ch2 != -1) {
12281 /*
12282 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12283 */
12284 predOp = &ctxt->comp->steps[op->ch2];
12285 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12286 if (predOp->ch1 != -1) {
12287 /*
12288 * Use the next inner predicate operator.
12289 */
12290 predOp = &ctxt->comp->steps[predOp->ch1];
12291 hasPredicateRange = 1;
12292 } else {
12293 /*
12294 * There's no other predicate than the [n] predicate.
12295 */
12296 predOp = NULL;
12297 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012298 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012299 }
12300 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012301 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012302 /*
12303 * Axis traversal -----------------------------------------------------
12304 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012305 /*
12306 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012307 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012308 * - For the namespace axis, the principal node type is namespace.
12309 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012310 *
12311 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012312 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012313 * select all element children of the context node
12314 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012315 oldContextNode = xpctxt->node;
12316 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012317 outSeq = NULL;
12318 seq = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012319 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012320 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012321
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012322
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012323 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12324 (ctxt->error == XPATH_EXPRESSION_OK)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012325 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012326
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012327 if (seq == NULL) {
12328 seq = xmlXPathNodeSetCreate(NULL);
12329 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012330 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012331 goto error;
12332 }
12333 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012334 /*
12335 * Traverse the axis and test the nodes.
12336 */
12337 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012338 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012339 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012340 do {
12341 cur = next(ctxt, cur);
12342 if (cur == NULL)
12343 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012344
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012345 /*
12346 * QUESTION TODO: What does the "first" and "last" stuff do?
12347 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012348 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012349 if (*first == cur)
12350 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012351 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012352#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012353 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012354#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012355 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012356#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012357 {
12358 break;
12359 }
12360 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012361 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012362 if (*last == cur)
12363 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012364 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012365#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012366 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012367#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012368 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012369#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012370 {
12371 break;
12372 }
12373 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012374
12375 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012376
Daniel Veillardf06307e2001-07-03 10:35:50 +000012377#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012378 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12379#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012380
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012381 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012382 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012383 total = 0;
12384 STRANGE
12385 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012386 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012387 if (type == NODE_TYPE_NODE) {
12388 switch (cur->type) {
12389 case XML_DOCUMENT_NODE:
12390 case XML_HTML_DOCUMENT_NODE:
12391#ifdef LIBXML_DOCB_ENABLED
12392 case XML_DOCB_DOCUMENT_NODE:
12393#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012394 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012395 case XML_ATTRIBUTE_NODE:
12396 case XML_PI_NODE:
12397 case XML_COMMENT_NODE:
12398 case XML_CDATA_SECTION_NODE:
12399 case XML_TEXT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012400 XP_TEST_HIT
12401 break;
Xin Li28c53d32017-03-07 00:33:02 +000012402 case XML_NAMESPACE_DECL: {
12403 if (axis == AXIS_NAMESPACE) {
12404 XP_TEST_HIT_NS
12405 } else {
12406 hasNsNodes = 1;
12407 XP_TEST_HIT
12408 }
12409 break;
12410 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012411 default:
12412 break;
12413 }
12414 } else if (cur->type == type) {
Daniel Veillard713434d2012-09-26 10:21:06 +080012415 if (cur->type == XML_NAMESPACE_DECL)
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012416 XP_TEST_HIT_NS
12417 else
12418 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012419 } else if ((type == NODE_TYPE_TEXT) &&
12420 (cur->type == XML_CDATA_SECTION_NODE))
12421 {
12422 XP_TEST_HIT
12423 }
12424 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012425 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012426 if ((cur->type == XML_PI_NODE) &&
12427 ((name == NULL) || xmlStrEqual(name, cur->name)))
12428 {
12429 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012430 }
12431 break;
12432 case NODE_TEST_ALL:
12433 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012434 if (cur->type == XML_ATTRIBUTE_NODE)
12435 {
Nick Wellnhofere8de99f2013-08-05 01:26:25 +020012436 if (prefix == NULL)
12437 {
12438 XP_TEST_HIT
12439 } else if ((cur->ns != NULL) &&
12440 (xmlStrEqual(URI, cur->ns->href)))
12441 {
12442 XP_TEST_HIT
12443 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012444 }
12445 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012446 if (cur->type == XML_NAMESPACE_DECL)
12447 {
12448 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012449 }
12450 } else {
12451 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012452 if (prefix == NULL)
12453 {
12454 XP_TEST_HIT
12455
Daniel Veillardf06307e2001-07-03 10:35:50 +000012456 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012457 (xmlStrEqual(URI, cur->ns->href)))
12458 {
12459 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012460 }
12461 }
12462 }
12463 break;
12464 case NODE_TEST_NS:{
12465 TODO;
12466 break;
12467 }
12468 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012469 if (axis == AXIS_ATTRIBUTE) {
12470 if (cur->type != XML_ATTRIBUTE_NODE)
12471 break;
12472 } else if (axis == AXIS_NAMESPACE) {
12473 if (cur->type != XML_NAMESPACE_DECL)
12474 break;
12475 } else {
12476 if (cur->type != XML_ELEMENT_NODE)
12477 break;
12478 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012479 switch (cur->type) {
12480 case XML_ELEMENT_NODE:
12481 if (xmlStrEqual(name, cur->name)) {
12482 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012483 if (cur->ns == NULL)
12484 {
12485 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012486 }
12487 } else {
12488 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012489 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012490 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012491 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012492 }
12493 }
12494 }
12495 break;
12496 case XML_ATTRIBUTE_NODE:{
12497 xmlAttrPtr attr = (xmlAttrPtr) cur;
12498
12499 if (xmlStrEqual(name, attr->name)) {
12500 if (prefix == NULL) {
12501 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012502 (attr->ns->prefix == NULL))
12503 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012504 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012505 }
12506 } else {
12507 if ((attr->ns != NULL) &&
12508 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012509 attr->ns->href)))
12510 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012511 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012512 }
12513 }
12514 }
12515 break;
12516 }
12517 case XML_NAMESPACE_DECL:
12518 if (cur->type == XML_NAMESPACE_DECL) {
12519 xmlNsPtr ns = (xmlNsPtr) cur;
12520
12521 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012522 && (xmlStrEqual(ns->prefix, name)))
12523 {
12524 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012525 }
12526 }
12527 break;
12528 default:
12529 break;
12530 }
12531 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012532 } /* switch(test) */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012533 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012534
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012535 goto apply_predicates;
12536
Daniel Veillard45490ae2008-07-29 09:13:19 +000012537axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012538 /*
12539 * We have a "/foo[n]", and position() = n was reached.
12540 * Note that we can have as well "/foo/::parent::foo[1]", so
12541 * a duplicate-aware merge is still needed.
12542 * Merge with the result.
12543 */
12544 if (outSeq == NULL) {
12545 outSeq = seq;
12546 seq = NULL;
12547 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012548 outSeq = mergeAndClear(outSeq, seq, 0);
12549 /*
12550 * Break if only a true/false result was requested.
12551 */
12552 if (toBool)
12553 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012554 continue;
12555
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012556first_hit: /* ---------------------------------------------------------- */
12557 /*
12558 * Break if only a true/false result was requested and
12559 * no predicates existed and a node test succeeded.
12560 */
12561 if (outSeq == NULL) {
12562 outSeq = seq;
12563 seq = NULL;
12564 } else
12565 outSeq = mergeAndClear(outSeq, seq, 0);
12566 break;
12567
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012568#ifdef DEBUG_STEP
12569 if (seq != NULL)
12570 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012571#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012572
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012573apply_predicates: /* --------------------------------------------------- */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012574 if (ctxt->error != XPATH_EXPRESSION_OK)
12575 goto error;
12576
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012577 /*
12578 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012579 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012580 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12581 /*
12582 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012583 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012584 /*
12585 * QUESTION TODO: The old predicate evaluation took into
12586 * account location-sets.
12587 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12588 * Do we expect such a set here?
12589 * All what I learned now from the evaluation semantics
12590 * does not indicate that a location-set will be processed
12591 * here, so this looks OK.
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012592 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012593 /*
12594 * Iterate over all predicates, starting with the outermost
12595 * predicate.
12596 * TODO: Problem: we cannot execute the inner predicates first
12597 * since we cannot go back *up* the operator tree!
12598 * Options we have:
12599 * 1) Use of recursive functions (like is it currently done
12600 * via xmlXPathCompOpEval())
12601 * 2) Add a predicate evaluation information stack to the
12602 * context struct
12603 * 3) Change the way the operators are linked; we need a
12604 * "parent" field on xmlXPathStepOp
12605 *
12606 * For the moment, I'll try to solve this with a recursive
12607 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012608 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012609 size = seq->nodeNr;
12610 if (hasPredicateRange != 0)
12611 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12612 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12613 else
12614 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12615 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012616
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012617 if (ctxt->error != XPATH_EXPRESSION_OK) {
12618 total = 0;
12619 goto error;
12620 }
12621 /*
12622 * Add the filtered set of nodes to the result node set.
12623 */
12624 if (newSize == 0) {
12625 /*
12626 * The predicates filtered all nodes out.
12627 */
12628 xmlXPathNodeSetClear(seq, hasNsNodes);
12629 } else if (seq->nodeNr > 0) {
12630 /*
12631 * Add to result set.
12632 */
12633 if (outSeq == NULL) {
12634 if (size != newSize) {
12635 /*
12636 * We need to merge and clear here, since
12637 * the sequence will contained NULLed entries.
12638 */
12639 outSeq = mergeAndClear(NULL, seq, 1);
12640 } else {
12641 outSeq = seq;
12642 seq = NULL;
12643 }
12644 } else
12645 outSeq = mergeAndClear(outSeq, seq,
12646 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012647 /*
12648 * Break if only a true/false result was requested.
12649 */
12650 if (toBool)
12651 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012652 }
12653 } else if (seq->nodeNr > 0) {
12654 /*
12655 * Add to result set.
12656 */
12657 if (outSeq == NULL) {
12658 outSeq = seq;
12659 seq = NULL;
12660 } else {
12661 outSeq = mergeAndClear(outSeq, seq, 0);
12662 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012663 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012664 }
12665
12666error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012667 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012668 /*
12669 * QUESTION TODO: What does this do and why?
12670 * TODO: Do we have to do this also for the "error"
12671 * cleanup further down?
12672 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012673 ctxt->value->boolval = 1;
12674 ctxt->value->user = obj->user;
12675 obj->user = NULL;
12676 obj->boolval = 0;
12677 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012678 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012679
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012680 /*
12681 * Ensure we return at least an emtpy set.
12682 */
12683 if (outSeq == NULL) {
12684 if ((seq != NULL) && (seq->nodeNr == 0))
12685 outSeq = seq;
12686 else
12687 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012688 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012689 }
12690 if ((seq != NULL) && (seq != outSeq)) {
12691 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012692 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012693 /*
12694 * Hand over the result. Better to push the set also in
12695 * case of errors.
12696 */
12697 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12698 /*
12699 * Reset the context node.
12700 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012701 xpctxt->node = oldContextNode;
Xin Li28c53d32017-03-07 00:33:02 +000012702 /*
12703 * When traversing the namespace axis in "toBool" mode, it's
12704 * possible that tmpNsList wasn't freed.
12705 */
12706 if (xpctxt->tmpNsList != NULL) {
12707 xmlFree(xpctxt->tmpNsList);
12708 xpctxt->tmpNsList = NULL;
12709 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012710
12711#ifdef DEBUG_STEP
12712 xmlGenericError(xmlGenericErrorContext,
12713 "\nExamined %d nodes, found %d nodes at that step\n",
12714 total, nbMatches);
12715#endif
12716
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012717 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012718}
12719
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012720static int
12721xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12722 xmlXPathStepOpPtr op, xmlNodePtr * first);
12723
Daniel Veillardf06307e2001-07-03 10:35:50 +000012724/**
12725 * xmlXPathCompOpEvalFirst:
12726 * @ctxt: the XPath parser context with the compiled expression
12727 * @op: an XPath compiled operation
12728 * @first: the first elem found so far
12729 *
12730 * Evaluate the Precompiled XPath operation searching only the first
12731 * element in document order
12732 *
12733 * Returns the number of examined objects.
12734 */
12735static int
12736xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12737 xmlXPathStepOpPtr op, xmlNodePtr * first)
12738{
12739 int total = 0, cur;
12740 xmlXPathCompExprPtr comp;
12741 xmlXPathObjectPtr arg1, arg2;
12742
Daniel Veillard556c6682001-10-06 09:59:51 +000012743 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012744 comp = ctxt->comp;
12745 switch (op->op) {
12746 case XPATH_OP_END:
12747 return (0);
12748 case XPATH_OP_UNION:
12749 total =
12750 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12751 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012752 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012753 if ((ctxt->value != NULL)
12754 && (ctxt->value->type == XPATH_NODESET)
12755 && (ctxt->value->nodesetval != NULL)
12756 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12757 /*
12758 * limit tree traversing to first node in the result
12759 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012760 /*
12761 * OPTIMIZE TODO: This implicitely sorts
12762 * the result, even if not needed. E.g. if the argument
12763 * of the count() function, no sorting is needed.
12764 * OPTIMIZE TODO: How do we know if the node-list wasn't
12765 * aready sorted?
12766 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012767 if (ctxt->value->nodesetval->nodeNr > 1)
12768 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012769 *first = ctxt->value->nodesetval->nodeTab[0];
12770 }
12771 cur =
12772 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12773 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012774 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012775 CHECK_TYPE0(XPATH_NODESET);
12776 arg2 = valuePop(ctxt);
12777
12778 CHECK_TYPE0(XPATH_NODESET);
12779 arg1 = valuePop(ctxt);
12780
12781 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12782 arg2->nodesetval);
12783 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012784 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012785 /* optimizer */
12786 if (total > cur)
12787 xmlXPathCompSwap(op);
12788 return (total + cur);
12789 case XPATH_OP_ROOT:
12790 xmlXPathRoot(ctxt);
12791 return (0);
12792 case XPATH_OP_NODE:
12793 if (op->ch1 != -1)
12794 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012795 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012796 if (op->ch2 != -1)
12797 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012798 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012799 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12800 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012801 return (total);
12802 case XPATH_OP_RESET:
12803 if (op->ch1 != -1)
12804 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012805 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012806 if (op->ch2 != -1)
12807 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012808 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012809 ctxt->context->node = NULL;
12810 return (total);
12811 case XPATH_OP_COLLECT:{
12812 if (op->ch1 == -1)
12813 return (total);
12814
12815 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012816 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012817
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012818 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012819 return (total);
12820 }
12821 case XPATH_OP_VALUE:
12822 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012823 xmlXPathCacheObjectCopy(ctxt->context,
12824 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012825 return (0);
12826 case XPATH_OP_SORT:
12827 if (op->ch1 != -1)
12828 total +=
12829 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12830 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012831 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012832 if ((ctxt->value != NULL)
12833 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012834 && (ctxt->value->nodesetval != NULL)
12835 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012836 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12837 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012838#ifdef XP_OPTIMIZED_FILTER_FIRST
12839 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012840 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012841 return (total);
12842#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012843 default:
12844 return (xmlXPathCompOpEval(ctxt, op));
12845 }
12846}
12847
12848/**
12849 * xmlXPathCompOpEvalLast:
12850 * @ctxt: the XPath parser context with the compiled expression
12851 * @op: an XPath compiled operation
12852 * @last: the last elem found so far
12853 *
12854 * Evaluate the Precompiled XPath operation searching only the last
12855 * element in document order
12856 *
William M. Brack08171912003-12-29 02:52:11 +000012857 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012858 */
12859static int
12860xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12861 xmlNodePtr * last)
12862{
12863 int total = 0, cur;
12864 xmlXPathCompExprPtr comp;
12865 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012866 xmlNodePtr bak;
12867 xmlDocPtr bakd;
12868 int pp;
12869 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012870
Daniel Veillard556c6682001-10-06 09:59:51 +000012871 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012872 comp = ctxt->comp;
12873 switch (op->op) {
12874 case XPATH_OP_END:
12875 return (0);
12876 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012877 bakd = ctxt->context->doc;
12878 bak = ctxt->context->node;
12879 pp = ctxt->context->proximityPosition;
12880 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012881 total =
12882 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012883 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012884 if ((ctxt->value != NULL)
12885 && (ctxt->value->type == XPATH_NODESET)
12886 && (ctxt->value->nodesetval != NULL)
12887 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12888 /*
12889 * limit tree traversing to first node in the result
12890 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012891 if (ctxt->value->nodesetval->nodeNr > 1)
12892 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012893 *last =
12894 ctxt->value->nodesetval->nodeTab[ctxt->value->
12895 nodesetval->nodeNr -
12896 1];
12897 }
William M. Brackce4fc562004-01-22 02:47:18 +000012898 ctxt->context->doc = bakd;
12899 ctxt->context->node = bak;
12900 ctxt->context->proximityPosition = pp;
12901 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012902 cur =
12903 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012904 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012905 if ((ctxt->value != NULL)
12906 && (ctxt->value->type == XPATH_NODESET)
12907 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012908 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012909 }
12910 CHECK_TYPE0(XPATH_NODESET);
12911 arg2 = valuePop(ctxt);
12912
12913 CHECK_TYPE0(XPATH_NODESET);
12914 arg1 = valuePop(ctxt);
12915
12916 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12917 arg2->nodesetval);
12918 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012919 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012920 /* optimizer */
12921 if (total > cur)
12922 xmlXPathCompSwap(op);
12923 return (total + cur);
12924 case XPATH_OP_ROOT:
12925 xmlXPathRoot(ctxt);
12926 return (0);
12927 case XPATH_OP_NODE:
12928 if (op->ch1 != -1)
12929 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012930 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012931 if (op->ch2 != -1)
12932 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012933 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012934 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12935 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012936 return (total);
12937 case XPATH_OP_RESET:
12938 if (op->ch1 != -1)
12939 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012940 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012941 if (op->ch2 != -1)
12942 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012943 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012944 ctxt->context->node = NULL;
12945 return (total);
12946 case XPATH_OP_COLLECT:{
12947 if (op->ch1 == -1)
12948 return (0);
12949
12950 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012951 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012952
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012953 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012954 return (total);
12955 }
12956 case XPATH_OP_VALUE:
12957 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012958 xmlXPathCacheObjectCopy(ctxt->context,
12959 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012960 return (0);
12961 case XPATH_OP_SORT:
12962 if (op->ch1 != -1)
12963 total +=
12964 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12965 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012966 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012967 if ((ctxt->value != NULL)
12968 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012969 && (ctxt->value->nodesetval != NULL)
12970 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012971 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12972 return (total);
12973 default:
12974 return (xmlXPathCompOpEval(ctxt, op));
12975 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012976}
12977
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012978#ifdef XP_OPTIMIZED_FILTER_FIRST
12979static int
12980xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12981 xmlXPathStepOpPtr op, xmlNodePtr * first)
12982{
12983 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012984 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012985 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012986 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012987 xmlNodeSetPtr oldset;
12988 xmlNodePtr oldnode;
12989 xmlDocPtr oldDoc;
12990 int i;
12991
12992 CHECK_ERROR0;
12993 comp = ctxt->comp;
12994 /*
12995 * Optimization for ()[last()] selection i.e. the last elem
12996 */
12997 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12998 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12999 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13000 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013001
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013002 if ((f != -1) &&
13003 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13004 (comp->steps[f].value5 == NULL) &&
13005 (comp->steps[f].value == 0) &&
13006 (comp->steps[f].value4 != NULL) &&
13007 (xmlStrEqual
13008 (comp->steps[f].value4, BAD_CAST "last"))) {
13009 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013010
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013011 total +=
13012 xmlXPathCompOpEvalLast(ctxt,
13013 &comp->steps[op->ch1],
13014 &last);
13015 CHECK_ERROR0;
13016 /*
13017 * The nodeset should be in document order,
13018 * Keep only the last value
13019 */
13020 if ((ctxt->value != NULL) &&
13021 (ctxt->value->type == XPATH_NODESET) &&
13022 (ctxt->value->nodesetval != NULL) &&
13023 (ctxt->value->nodesetval->nodeTab != NULL) &&
13024 (ctxt->value->nodesetval->nodeNr > 1)) {
13025 ctxt->value->nodesetval->nodeTab[0] =
13026 ctxt->value->nodesetval->nodeTab[ctxt->
13027 value->
13028 nodesetval->
13029 nodeNr -
13030 1];
13031 ctxt->value->nodesetval->nodeNr = 1;
13032 *first = *(ctxt->value->nodesetval->nodeTab);
13033 }
13034 return (total);
13035 }
13036 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013037
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013038 if (op->ch1 != -1)
13039 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13040 CHECK_ERROR0;
13041 if (op->ch2 == -1)
13042 return (total);
13043 if (ctxt->value == NULL)
13044 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013045
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013046#ifdef LIBXML_XPTR_ENABLED
13047 oldnode = ctxt->context->node;
13048 /*
13049 * Hum are we filtering the result of an XPointer expression
13050 */
13051 if (ctxt->value->type == XPATH_LOCATIONSET) {
13052 xmlXPathObjectPtr tmp = NULL;
13053 xmlLocationSetPtr newlocset = NULL;
13054 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013055
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013056 /*
13057 * Extract the old locset, and then evaluate the result of the
13058 * expression for all the element in the locset. use it to grow
13059 * up a new locset.
13060 */
13061 CHECK_TYPE0(XPATH_LOCATIONSET);
13062 obj = valuePop(ctxt);
13063 oldlocset = obj->user;
13064 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013065
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013066 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13067 ctxt->context->contextSize = 0;
13068 ctxt->context->proximityPosition = 0;
13069 if (op->ch2 != -1)
13070 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13071 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013072 if (res != NULL) {
13073 xmlXPathReleaseObject(ctxt->context, res);
13074 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013075 valuePush(ctxt, obj);
13076 CHECK_ERROR0;
13077 return (total);
13078 }
13079 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013080
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013081 for (i = 0; i < oldlocset->locNr; i++) {
13082 /*
13083 * Run the evaluation with a node list made of a
13084 * single item in the nodelocset.
13085 */
13086 ctxt->context->node = oldlocset->locTab[i]->user;
13087 ctxt->context->contextSize = oldlocset->locNr;
13088 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013089 if (tmp == NULL) {
13090 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13091 ctxt->context->node);
13092 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013093 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13094 ctxt->context->node) < 0) {
13095 ctxt->error = XPATH_MEMORY_ERROR;
13096 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013097 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013098 valuePush(ctxt, tmp);
13099 if (op->ch2 != -1)
13100 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13101 if (ctxt->error != XPATH_EXPRESSION_OK) {
13102 xmlXPathFreeObject(obj);
13103 return(0);
13104 }
13105 /*
13106 * The result of the evaluation need to be tested to
13107 * decided whether the filter succeeded or not
13108 */
13109 res = valuePop(ctxt);
13110 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13111 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013112 xmlXPathCacheObjectCopy(ctxt->context,
13113 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013114 }
13115 /*
13116 * Cleanup
13117 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013118 if (res != NULL) {
13119 xmlXPathReleaseObject(ctxt->context, res);
13120 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013121 if (ctxt->value == tmp) {
13122 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013123 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013124 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013125 * REVISIT TODO: Don't create a temporary nodeset
13126 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013127 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013128 /* OLD: xmlXPathFreeObject(res); */
13129 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013130 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013131 ctxt->context->node = NULL;
13132 /*
13133 * Only put the first node in the result, then leave.
13134 */
13135 if (newlocset->locNr > 0) {
13136 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13137 break;
13138 }
13139 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013140 if (tmp != NULL) {
13141 xmlXPathReleaseObject(ctxt->context, tmp);
13142 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013143 /*
13144 * The result is used as the new evaluation locset.
13145 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013146 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013147 ctxt->context->node = NULL;
13148 ctxt->context->contextSize = -1;
13149 ctxt->context->proximityPosition = -1;
13150 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13151 ctxt->context->node = oldnode;
13152 return (total);
13153 }
13154#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013155
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013156 /*
13157 * Extract the old set, and then evaluate the result of the
13158 * expression for all the element in the set. use it to grow
13159 * up a new set.
13160 */
13161 CHECK_TYPE0(XPATH_NODESET);
13162 obj = valuePop(ctxt);
13163 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013164
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013165 oldnode = ctxt->context->node;
13166 oldDoc = ctxt->context->doc;
13167 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013168
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013169 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13170 ctxt->context->contextSize = 0;
13171 ctxt->context->proximityPosition = 0;
13172 /* QUESTION TODO: Why was this code commented out?
13173 if (op->ch2 != -1)
13174 total +=
13175 xmlXPathCompOpEval(ctxt,
13176 &comp->steps[op->ch2]);
13177 CHECK_ERROR0;
13178 res = valuePop(ctxt);
13179 if (res != NULL)
13180 xmlXPathFreeObject(res);
13181 */
13182 valuePush(ctxt, obj);
13183 ctxt->context->node = oldnode;
13184 CHECK_ERROR0;
13185 } else {
13186 xmlNodeSetPtr newset;
13187 xmlXPathObjectPtr tmp = NULL;
13188 /*
13189 * Initialize the new set.
13190 * Also set the xpath document in case things like
13191 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013192 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013193 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013194 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013195
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013196 for (i = 0; i < oldset->nodeNr; i++) {
13197 /*
13198 * Run the evaluation with a node list made of
13199 * a single item in the nodeset.
13200 */
13201 ctxt->context->node = oldset->nodeTab[i];
13202 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13203 (oldset->nodeTab[i]->doc != NULL))
13204 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013205 if (tmp == NULL) {
13206 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13207 ctxt->context->node);
13208 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013209 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13210 ctxt->context->node) < 0) {
13211 ctxt->error = XPATH_MEMORY_ERROR;
13212 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013213 }
13214 valuePush(ctxt, tmp);
13215 ctxt->context->contextSize = oldset->nodeNr;
13216 ctxt->context->proximityPosition = i + 1;
13217 if (op->ch2 != -1)
13218 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13219 if (ctxt->error != XPATH_EXPRESSION_OK) {
13220 xmlXPathFreeNodeSet(newset);
13221 xmlXPathFreeObject(obj);
13222 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013223 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013224 /*
13225 * The result of the evaluation needs to be tested to
13226 * decide whether the filter succeeded or not
13227 */
13228 res = valuePop(ctxt);
13229 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013230 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13231 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013232 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013233 /*
13234 * Cleanup
13235 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013236 if (res != NULL) {
13237 xmlXPathReleaseObject(ctxt->context, res);
13238 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013239 if (ctxt->value == tmp) {
13240 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013241 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013242 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013243 * in order to avoid massive recreation inside this
13244 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013245 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013246 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013247 } else
13248 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013249 ctxt->context->node = NULL;
13250 /*
13251 * Only put the first node in the result, then leave.
13252 */
13253 if (newset->nodeNr > 0) {
13254 *first = *(newset->nodeTab);
13255 break;
13256 }
13257 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013258 if (tmp != NULL) {
13259 xmlXPathReleaseObject(ctxt->context, tmp);
13260 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013261 /*
13262 * The result is used as the new evaluation set.
13263 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013264 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013265 ctxt->context->node = NULL;
13266 ctxt->context->contextSize = -1;
13267 ctxt->context->proximityPosition = -1;
13268 /* may want to move this past the '}' later */
13269 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013270 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013271 }
13272 ctxt->context->node = oldnode;
13273 return(total);
13274}
13275#endif /* XP_OPTIMIZED_FILTER_FIRST */
13276
Owen Taylor3473f882001-02-23 17:55:21 +000013277/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013278 * xmlXPathCompOpEval:
13279 * @ctxt: the XPath parser context with the compiled expression
13280 * @op: an XPath compiled operation
13281 *
13282 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013283 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013284 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013285static int
13286xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13287{
13288 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013289 int equal, ret;
13290 xmlXPathCompExprPtr comp;
13291 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013292 xmlNodePtr bak;
13293 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013294 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013295 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013296
Daniel Veillard556c6682001-10-06 09:59:51 +000013297 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013298 comp = ctxt->comp;
13299 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013300 case XPATH_OP_END:
13301 return (0);
13302 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013303 bakd = ctxt->context->doc;
13304 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013305 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013306 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013307 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013308 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013309 xmlXPathBooleanFunction(ctxt, 1);
13310 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13311 return (total);
13312 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013313 ctxt->context->doc = bakd;
13314 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013315 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013316 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013317 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013318 if (ctxt->error) {
13319 xmlXPathFreeObject(arg2);
13320 return(0);
13321 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013322 xmlXPathBooleanFunction(ctxt, 1);
13323 arg1 = valuePop(ctxt);
13324 arg1->boolval &= arg2->boolval;
13325 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013326 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013327 return (total);
13328 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013329 bakd = ctxt->context->doc;
13330 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013331 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013332 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013333 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013334 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013335 xmlXPathBooleanFunction(ctxt, 1);
13336 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13337 return (total);
13338 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013339 ctxt->context->doc = bakd;
13340 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013341 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013342 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013343 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013344 if (ctxt->error) {
13345 xmlXPathFreeObject(arg2);
13346 return(0);
13347 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013348 xmlXPathBooleanFunction(ctxt, 1);
13349 arg1 = valuePop(ctxt);
13350 arg1->boolval |= arg2->boolval;
13351 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013352 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013353 return (total);
13354 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013355 bakd = ctxt->context->doc;
13356 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013357 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013358 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013359 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013360 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013361 ctxt->context->doc = bakd;
13362 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013363 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013364 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013365 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013366 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013367 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013368 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013369 else
13370 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013371 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013372 return (total);
13373 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013374 bakd = ctxt->context->doc;
13375 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013376 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013377 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013378 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013379 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013380 ctxt->context->doc = bakd;
13381 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013382 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013383 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013384 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013385 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013386 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013387 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013388 return (total);
13389 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013390 bakd = ctxt->context->doc;
13391 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013392 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013393 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013394 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013395 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013396 if (op->ch2 != -1) {
13397 ctxt->context->doc = bakd;
13398 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013399 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013400 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013401 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013402 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013403 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013404 if (op->value == 0)
13405 xmlXPathSubValues(ctxt);
13406 else if (op->value == 1)
13407 xmlXPathAddValues(ctxt);
13408 else if (op->value == 2)
13409 xmlXPathValueFlipSign(ctxt);
13410 else if (op->value == 3) {
13411 CAST_TO_NUMBER;
13412 CHECK_TYPE0(XPATH_NUMBER);
13413 }
13414 return (total);
13415 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013416 bakd = ctxt->context->doc;
13417 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013418 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013419 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013420 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013421 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013422 ctxt->context->doc = bakd;
13423 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013424 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013425 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013426 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013427 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013428 if (op->value == 0)
13429 xmlXPathMultValues(ctxt);
13430 else if (op->value == 1)
13431 xmlXPathDivValues(ctxt);
13432 else if (op->value == 2)
13433 xmlXPathModValues(ctxt);
13434 return (total);
13435 case XPATH_OP_UNION:
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 CHECK_TYPE0(XPATH_NODESET);
13449 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013450
Daniel Veillardf06307e2001-07-03 10:35:50 +000013451 CHECK_TYPE0(XPATH_NODESET);
13452 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013453
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013454 if ((arg1->nodesetval == NULL) ||
13455 ((arg2->nodesetval != NULL) &&
13456 (arg2->nodesetval->nodeNr != 0)))
13457 {
13458 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13459 arg2->nodesetval);
13460 }
13461
Daniel Veillardf06307e2001-07-03 10:35:50 +000013462 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013463 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013464 return (total);
13465 case XPATH_OP_ROOT:
13466 xmlXPathRoot(ctxt);
13467 return (total);
13468 case XPATH_OP_NODE:
13469 if (op->ch1 != -1)
13470 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013471 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013472 if (op->ch2 != -1)
13473 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013474 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013475 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13476 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013477 return (total);
13478 case XPATH_OP_RESET:
13479 if (op->ch1 != -1)
13480 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013481 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013482 if (op->ch2 != -1)
13483 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013484 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013485 ctxt->context->node = NULL;
13486 return (total);
13487 case XPATH_OP_COLLECT:{
13488 if (op->ch1 == -1)
13489 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013490
Daniel Veillardf06307e2001-07-03 10:35:50 +000013491 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013492 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013493
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013494 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013495 return (total);
13496 }
13497 case XPATH_OP_VALUE:
13498 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013499 xmlXPathCacheObjectCopy(ctxt->context,
13500 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013501 return (total);
13502 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013503 xmlXPathObjectPtr val;
13504
Daniel Veillardf06307e2001-07-03 10:35:50 +000013505 if (op->ch1 != -1)
13506 total +=
13507 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013508 if (op->value5 == NULL) {
13509 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13510 if (val == NULL) {
13511 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13512 return(0);
13513 }
13514 valuePush(ctxt, val);
13515 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013516 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013517
Daniel Veillardf06307e2001-07-03 10:35:50 +000013518 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13519 if (URI == NULL) {
13520 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013521 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13522 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013523 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013524 return (total);
13525 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013526 val = xmlXPathVariableLookupNS(ctxt->context,
13527 op->value4, URI);
13528 if (val == NULL) {
13529 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13530 return(0);
13531 }
13532 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013533 }
13534 return (total);
13535 }
13536 case XPATH_OP_FUNCTION:{
13537 xmlXPathFunction func;
13538 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013539 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013540 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013541
Daniel Veillardf5048b32011-08-18 17:10:13 +080013542 frame = xmlXPathSetFrame(ctxt);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013543 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013544 total +=
13545 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer03c67232013-12-20 00:01:53 +010013546 if (ctxt->error != XPATH_EXPRESSION_OK) {
13547 xmlXPathPopFrame(ctxt, frame);
13548 return (total);
13549 }
13550 }
13551 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013552 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013553 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013554 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013555 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013556 return (total);
13557 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013558 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013559 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13560 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013561 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013562 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013563 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013564 return (total);
13565 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013566 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013567 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013568 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013569 else {
13570 const xmlChar *URI = NULL;
13571
13572 if (op->value5 == NULL)
13573 func =
13574 xmlXPathFunctionLookup(ctxt->context,
13575 op->value4);
13576 else {
13577 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13578 if (URI == NULL) {
13579 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013580 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13581 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013582 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013583 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013584 return (total);
13585 }
13586 func = xmlXPathFunctionLookupNS(ctxt->context,
13587 op->value4, URI);
13588 }
13589 if (func == NULL) {
13590 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013591 "xmlXPathCompOpEval: function %s not found\n",
13592 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013593 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013594 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013595 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013596 op->cacheURI = (void *) URI;
13597 }
13598 oldFunc = ctxt->context->function;
13599 oldFuncURI = ctxt->context->functionURI;
13600 ctxt->context->function = op->value4;
13601 ctxt->context->functionURI = op->cacheURI;
13602 func(ctxt, op->value);
13603 ctxt->context->function = oldFunc;
13604 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013605 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013606 return (total);
13607 }
13608 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013609 bakd = ctxt->context->doc;
13610 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013611 pp = ctxt->context->proximityPosition;
13612 cs = ctxt->context->contextSize;
Nick Wellnhofer07def302014-03-21 19:38:08 +010013613 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013614 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013615 ctxt->context->contextSize = cs;
13616 ctxt->context->proximityPosition = pp;
13617 ctxt->context->node = bak;
13618 ctxt->context->doc = bakd;
13619 CHECK_ERROR0;
13620 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013621 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013622 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Nick Wellnhofer07def302014-03-21 19:38:08 +010013623 ctxt->context->contextSize = cs;
13624 ctxt->context->proximityPosition = pp;
13625 ctxt->context->node = bak;
13626 ctxt->context->doc = bakd;
William M. Brack72ee48d2003-12-30 08:30:19 +000013627 CHECK_ERROR0;
13628 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013629 return (total);
13630 case XPATH_OP_PREDICATE:
13631 case XPATH_OP_FILTER:{
13632 xmlXPathObjectPtr res;
13633 xmlXPathObjectPtr obj, tmp;
13634 xmlNodeSetPtr newset = NULL;
13635 xmlNodeSetPtr oldset;
13636 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013637 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013638 int i;
13639
13640 /*
13641 * Optimization for ()[1] selection i.e. the first elem
13642 */
13643 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013644#ifdef XP_OPTIMIZED_FILTER_FIRST
13645 /*
13646 * FILTER TODO: Can we assume that the inner processing
13647 * will result in an ordered list if we have an
13648 * XPATH_OP_FILTER?
13649 * What about an additional field or flag on
13650 * xmlXPathObject like @sorted ? This way we wouln'd need
13651 * to assume anything, so it would be more robust and
13652 * easier to optimize.
13653 */
13654 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13655 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13656#else
13657 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13658#endif
13659 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013660 xmlXPathObjectPtr val;
13661
13662 val = comp->steps[op->ch2].value4;
13663 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13664 (val->floatval == 1.0)) {
13665 xmlNodePtr first = NULL;
13666
13667 total +=
13668 xmlXPathCompOpEvalFirst(ctxt,
13669 &comp->steps[op->ch1],
13670 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013671 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013672 /*
13673 * The nodeset should be in document order,
13674 * Keep only the first value
13675 */
13676 if ((ctxt->value != NULL) &&
13677 (ctxt->value->type == XPATH_NODESET) &&
13678 (ctxt->value->nodesetval != NULL) &&
13679 (ctxt->value->nodesetval->nodeNr > 1))
13680 ctxt->value->nodesetval->nodeNr = 1;
13681 return (total);
13682 }
13683 }
13684 /*
13685 * Optimization for ()[last()] selection i.e. the last elem
13686 */
13687 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13688 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13689 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13690 int f = comp->steps[op->ch2].ch1;
13691
13692 if ((f != -1) &&
13693 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13694 (comp->steps[f].value5 == NULL) &&
13695 (comp->steps[f].value == 0) &&
13696 (comp->steps[f].value4 != NULL) &&
13697 (xmlStrEqual
13698 (comp->steps[f].value4, BAD_CAST "last"))) {
13699 xmlNodePtr last = NULL;
13700
13701 total +=
13702 xmlXPathCompOpEvalLast(ctxt,
13703 &comp->steps[op->ch1],
13704 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013705 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013706 /*
13707 * The nodeset should be in document order,
13708 * Keep only the last value
13709 */
13710 if ((ctxt->value != NULL) &&
13711 (ctxt->value->type == XPATH_NODESET) &&
13712 (ctxt->value->nodesetval != NULL) &&
13713 (ctxt->value->nodesetval->nodeTab != NULL) &&
13714 (ctxt->value->nodesetval->nodeNr > 1)) {
13715 ctxt->value->nodesetval->nodeTab[0] =
13716 ctxt->value->nodesetval->nodeTab[ctxt->
13717 value->
13718 nodesetval->
13719 nodeNr -
13720 1];
13721 ctxt->value->nodesetval->nodeNr = 1;
13722 }
13723 return (total);
13724 }
13725 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013726 /*
13727 * Process inner predicates first.
13728 * Example "index[parent::book][1]":
13729 * ...
13730 * PREDICATE <-- we are here "[1]"
13731 * PREDICATE <-- process "[parent::book]" first
13732 * SORT
13733 * COLLECT 'parent' 'name' 'node' book
13734 * NODE
13735 * ELEM Object is a number : 1
13736 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013737 if (op->ch1 != -1)
13738 total +=
13739 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013740 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013741 if (op->ch2 == -1)
13742 return (total);
13743 if (ctxt->value == NULL)
13744 return (total);
13745
13746 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013747
13748#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013749 /*
13750 * Hum are we filtering the result of an XPointer expression
13751 */
13752 if (ctxt->value->type == XPATH_LOCATIONSET) {
13753 xmlLocationSetPtr newlocset = NULL;
13754 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013755
Daniel Veillardf06307e2001-07-03 10:35:50 +000013756 /*
13757 * Extract the old locset, and then evaluate the result of the
13758 * expression for all the element in the locset. use it to grow
13759 * up a new locset.
13760 */
13761 CHECK_TYPE0(XPATH_LOCATIONSET);
13762 obj = valuePop(ctxt);
13763 oldlocset = obj->user;
13764 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013765
Daniel Veillardf06307e2001-07-03 10:35:50 +000013766 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13767 ctxt->context->contextSize = 0;
13768 ctxt->context->proximityPosition = 0;
13769 if (op->ch2 != -1)
13770 total +=
13771 xmlXPathCompOpEval(ctxt,
13772 &comp->steps[op->ch2]);
13773 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013774 if (res != NULL) {
13775 xmlXPathReleaseObject(ctxt->context, res);
13776 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013777 valuePush(ctxt, obj);
13778 CHECK_ERROR0;
13779 return (total);
13780 }
13781 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013782
Daniel Veillardf06307e2001-07-03 10:35:50 +000013783 for (i = 0; i < oldlocset->locNr; i++) {
13784 /*
13785 * Run the evaluation with a node list made of a
13786 * single item in the nodelocset.
13787 */
13788 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013789 ctxt->context->contextSize = oldlocset->locNr;
13790 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013791 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13792 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013793 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013794
Daniel Veillardf06307e2001-07-03 10:35:50 +000013795 if (op->ch2 != -1)
13796 total +=
13797 xmlXPathCompOpEval(ctxt,
13798 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013799 if (ctxt->error != XPATH_EXPRESSION_OK) {
13800 xmlXPathFreeObject(obj);
13801 return(0);
13802 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013803
Daniel Veillardf06307e2001-07-03 10:35:50 +000013804 /*
13805 * The result of the evaluation need to be tested to
13806 * decided whether the filter succeeded or not
13807 */
13808 res = valuePop(ctxt);
13809 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13810 xmlXPtrLocationSetAdd(newlocset,
13811 xmlXPathObjectCopy
13812 (oldlocset->locTab[i]));
13813 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013814
Daniel Veillardf06307e2001-07-03 10:35:50 +000013815 /*
13816 * Cleanup
13817 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013818 if (res != NULL) {
13819 xmlXPathReleaseObject(ctxt->context, res);
13820 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013821 if (ctxt->value == tmp) {
13822 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013823 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013824 }
13825
13826 ctxt->context->node = NULL;
13827 }
13828
13829 /*
13830 * The result is used as the new evaluation locset.
13831 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013832 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013833 ctxt->context->node = NULL;
13834 ctxt->context->contextSize = -1;
13835 ctxt->context->proximityPosition = -1;
13836 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13837 ctxt->context->node = oldnode;
13838 return (total);
13839 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013840#endif /* LIBXML_XPTR_ENABLED */
13841
Daniel Veillardf06307e2001-07-03 10:35:50 +000013842 /*
13843 * Extract the old set, and then evaluate the result of the
13844 * expression for all the element in the set. use it to grow
13845 * up a new set.
13846 */
13847 CHECK_TYPE0(XPATH_NODESET);
13848 obj = valuePop(ctxt);
13849 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013850
Daniel Veillardf06307e2001-07-03 10:35:50 +000013851 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013852 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013853 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013854
Daniel Veillardf06307e2001-07-03 10:35:50 +000013855 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13856 ctxt->context->contextSize = 0;
13857 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013858/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013859 if (op->ch2 != -1)
13860 total +=
13861 xmlXPathCompOpEval(ctxt,
13862 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013863 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013864 res = valuePop(ctxt);
13865 if (res != NULL)
13866 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013867*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013868 valuePush(ctxt, obj);
13869 ctxt->context->node = oldnode;
13870 CHECK_ERROR0;
13871 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013872 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013873 /*
13874 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013875 * Also set the xpath document in case things like
13876 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013877 */
13878 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013879 /*
13880 * SPEC XPath 1.0:
13881 * "For each node in the node-set to be filtered, the
13882 * PredicateExpr is evaluated with that node as the
13883 * context node, with the number of nodes in the
13884 * node-set as the context size, and with the proximity
13885 * position of the node in the node-set with respect to
13886 * the axis as the context position;"
13887 * @oldset is the node-set" to be filtered.
13888 *
13889 * SPEC XPath 1.0:
13890 * "only predicates change the context position and
13891 * context size (see [2.4 Predicates])."
13892 * Example:
13893 * node-set context pos
13894 * nA 1
13895 * nB 2
13896 * nC 3
13897 * After applying predicate [position() > 1] :
13898 * node-set context pos
13899 * nB 1
13900 * nC 2
13901 *
13902 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013903 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013904 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013905 for (i = 0; i < oldset->nodeNr; i++) {
13906 /*
13907 * Run the evaluation with a node list made of
13908 * a single item in the nodeset.
13909 */
13910 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013911 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13912 (oldset->nodeTab[i]->doc != NULL))
13913 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013914 if (tmp == NULL) {
13915 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13916 ctxt->context->node);
13917 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013918 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13919 ctxt->context->node) < 0) {
13920 ctxt->error = XPATH_MEMORY_ERROR;
13921 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013922 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013923 valuePush(ctxt, tmp);
13924 ctxt->context->contextSize = oldset->nodeNr;
13925 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013926 /*
13927 * Evaluate the predicate against the context node.
13928 * Can/should we optimize position() predicates
13929 * here (e.g. "[1]")?
13930 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013931 if (op->ch2 != -1)
13932 total +=
13933 xmlXPathCompOpEval(ctxt,
13934 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013935 if (ctxt->error != XPATH_EXPRESSION_OK) {
13936 xmlXPathFreeNodeSet(newset);
13937 xmlXPathFreeObject(obj);
13938 return(0);
13939 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013940
Daniel Veillardf06307e2001-07-03 10:35:50 +000013941 /*
William M. Brack08171912003-12-29 02:52:11 +000013942 * The result of the evaluation needs to be tested to
13943 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013944 */
13945 /*
13946 * OPTIMIZE TODO: Can we use
13947 * xmlXPathNodeSetAdd*Unique()* instead?
13948 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013949 res = valuePop(ctxt);
13950 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013951 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13952 < 0)
13953 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013954 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013955
Daniel Veillardf06307e2001-07-03 10:35:50 +000013956 /*
13957 * Cleanup
13958 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013959 if (res != NULL) {
13960 xmlXPathReleaseObject(ctxt->context, res);
13961 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013962 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013963 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013964 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013965 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013966 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013967 * in order to avoid massive recreation inside this
13968 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013969 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013970 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013971 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013972 ctxt->context->node = NULL;
13973 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013974 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013975 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013976 /*
13977 * The result is used as the new evaluation set.
13978 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013979 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013980 ctxt->context->node = NULL;
13981 ctxt->context->contextSize = -1;
13982 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013983 /* may want to move this past the '}' later */
13984 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013985 valuePush(ctxt,
13986 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013987 }
13988 ctxt->context->node = oldnode;
13989 return (total);
13990 }
13991 case XPATH_OP_SORT:
13992 if (op->ch1 != -1)
13993 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013994 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013995 if ((ctxt->value != NULL) &&
13996 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013997 (ctxt->value->nodesetval != NULL) &&
13998 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013999 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014000 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014001 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014002 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014003#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000014004 case XPATH_OP_RANGETO:{
14005 xmlXPathObjectPtr range;
14006 xmlXPathObjectPtr res, obj;
14007 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000014008 xmlLocationSetPtr newlocset = NULL;
14009 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014010 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000014011 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014012
Xin Li28c53d32017-03-07 00:33:02 +000014013 if (op->ch1 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014014 total +=
14015 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Xin Li28c53d32017-03-07 00:33:02 +000014016 CHECK_ERROR0;
14017 }
14018 if (ctxt->value == NULL) {
14019 XP_ERROR0(XPATH_INVALID_OPERAND);
14020 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014021 if (op->ch2 == -1)
14022 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014023
William M. Brack08171912003-12-29 02:52:11 +000014024 if (ctxt->value->type == XPATH_LOCATIONSET) {
14025 /*
14026 * Extract the old locset, and then evaluate the result of the
14027 * expression for all the element in the locset. use it to grow
14028 * up a new locset.
14029 */
14030 CHECK_TYPE0(XPATH_LOCATIONSET);
14031 obj = valuePop(ctxt);
14032 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014033
William M. Brack08171912003-12-29 02:52:11 +000014034 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000014035 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000014036 ctxt->context->contextSize = 0;
14037 ctxt->context->proximityPosition = 0;
14038 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14039 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014040 if (res != NULL) {
14041 xmlXPathReleaseObject(ctxt->context, res);
14042 }
William M. Brack08171912003-12-29 02:52:11 +000014043 valuePush(ctxt, obj);
14044 CHECK_ERROR0;
14045 return (total);
14046 }
14047 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014048
William M. Brack08171912003-12-29 02:52:11 +000014049 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014050 /*
William M. Brack08171912003-12-29 02:52:11 +000014051 * Run the evaluation with a node list made of a
14052 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000014053 */
William M. Brackf7eb7942003-12-31 07:59:17 +000014054 ctxt->context->node = oldlocset->locTab[i]->user;
14055 ctxt->context->contextSize = oldlocset->locNr;
14056 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014057 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14058 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014059 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014060
Daniel Veillardf06307e2001-07-03 10:35:50 +000014061 if (op->ch2 != -1)
14062 total +=
14063 xmlXPathCompOpEval(ctxt,
14064 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014065 if (ctxt->error != XPATH_EXPRESSION_OK) {
14066 xmlXPathFreeObject(obj);
14067 return(0);
14068 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014069
Daniel Veillardf06307e2001-07-03 10:35:50 +000014070 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000014071 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014072 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000014073 (xmlLocationSetPtr)res->user;
14074 for (j=0; j<rloc->locNr; j++) {
14075 range = xmlXPtrNewRange(
14076 oldlocset->locTab[i]->user,
14077 oldlocset->locTab[i]->index,
14078 rloc->locTab[j]->user2,
14079 rloc->locTab[j]->index2);
14080 if (range != NULL) {
14081 xmlXPtrLocationSetAdd(newlocset, range);
14082 }
14083 }
14084 } else {
14085 range = xmlXPtrNewRangeNodeObject(
14086 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14087 if (range != NULL) {
14088 xmlXPtrLocationSetAdd(newlocset,range);
14089 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014090 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014091
Daniel Veillardf06307e2001-07-03 10:35:50 +000014092 /*
14093 * Cleanup
14094 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014095 if (res != NULL) {
14096 xmlXPathReleaseObject(ctxt->context, res);
14097 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014098 if (ctxt->value == tmp) {
14099 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014100 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014101 }
14102
14103 ctxt->context->node = NULL;
14104 }
William M. Brack72ee48d2003-12-30 08:30:19 +000014105 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000014106 CHECK_TYPE0(XPATH_NODESET);
14107 obj = valuePop(ctxt);
14108 oldset = obj->nodesetval;
14109 ctxt->context->node = NULL;
14110
14111 newlocset = xmlXPtrLocationSetCreate(NULL);
14112
14113 if (oldset != NULL) {
14114 for (i = 0; i < oldset->nodeNr; i++) {
14115 /*
14116 * Run the evaluation with a node list made of a single item
14117 * in the nodeset.
14118 */
14119 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014120 /*
14121 * OPTIMIZE TODO: Avoid recreation for every iteration.
14122 */
14123 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14124 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000014125 valuePush(ctxt, tmp);
14126
14127 if (op->ch2 != -1)
14128 total +=
14129 xmlXPathCompOpEval(ctxt,
14130 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014131 if (ctxt->error != XPATH_EXPRESSION_OK) {
14132 xmlXPathFreeObject(obj);
14133 return(0);
14134 }
William M. Brack08171912003-12-29 02:52:11 +000014135
William M. Brack08171912003-12-29 02:52:11 +000014136 res = valuePop(ctxt);
14137 range =
14138 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14139 res);
14140 if (range != NULL) {
14141 xmlXPtrLocationSetAdd(newlocset, range);
14142 }
14143
14144 /*
14145 * Cleanup
14146 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014147 if (res != NULL) {
14148 xmlXPathReleaseObject(ctxt->context, res);
14149 }
William M. Brack08171912003-12-29 02:52:11 +000014150 if (ctxt->value == tmp) {
14151 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014152 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000014153 }
14154
14155 ctxt->context->node = NULL;
14156 }
14157 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014158 }
14159
14160 /*
14161 * The result is used as the new evaluation set.
14162 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014163 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014164 ctxt->context->node = NULL;
14165 ctxt->context->contextSize = -1;
14166 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000014167 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014168 return (total);
14169 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014170#endif /* LIBXML_XPTR_ENABLED */
14171 }
14172 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000014173 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080014174 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014175 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014176}
14177
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014178/**
14179 * xmlXPathCompOpEvalToBoolean:
14180 * @ctxt: the XPath parser context
14181 *
14182 * Evaluates if the expression evaluates to true.
14183 *
14184 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14185 */
14186static int
14187xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014188 xmlXPathStepOpPtr op,
14189 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014190{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014191 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014192
14193start:
14194 /* comp = ctxt->comp; */
14195 switch (op->op) {
14196 case XPATH_OP_END:
14197 return (0);
14198 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014199 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014200 if (isPredicate)
14201 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14202 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014203 case XPATH_OP_SORT:
14204 /*
14205 * We don't need sorting for boolean results. Skip this one.
14206 */
14207 if (op->ch1 != -1) {
14208 op = &ctxt->comp->steps[op->ch1];
14209 goto start;
14210 }
14211 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014212 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014213 if (op->ch1 == -1)
14214 return(0);
14215
14216 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14217 if (ctxt->error != XPATH_EXPRESSION_OK)
14218 return(-1);
14219
14220 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14221 if (ctxt->error != XPATH_EXPRESSION_OK)
14222 return(-1);
14223
14224 resObj = valuePop(ctxt);
14225 if (resObj == NULL)
14226 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014227 break;
14228 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014229 /*
14230 * Fallback to call xmlXPathCompOpEval().
14231 */
14232 xmlXPathCompOpEval(ctxt, op);
14233 if (ctxt->error != XPATH_EXPRESSION_OK)
14234 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014235
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014236 resObj = valuePop(ctxt);
14237 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014238 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014239 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014240 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014241
14242 if (resObj) {
14243 int res;
14244
14245 if (resObj->type == XPATH_BOOLEAN) {
14246 res = resObj->boolval;
14247 } else if (isPredicate) {
14248 /*
14249 * For predicates a result of type "number" is handled
14250 * differently:
14251 * SPEC XPath 1.0:
14252 * "If the result is a number, the result will be converted
14253 * to true if the number is equal to the context position
14254 * and will be converted to false otherwise;"
14255 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014256 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014257 } else {
14258 res = xmlXPathCastToBoolean(resObj);
14259 }
14260 xmlXPathReleaseObject(ctxt->context, resObj);
14261 return(res);
14262 }
14263
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014264 return(0);
14265}
14266
Daniel Veillard56de87e2005-02-16 00:22:29 +000014267#ifdef XPATH_STREAMING
14268/**
14269 * xmlXPathRunStreamEval:
14270 * @ctxt: the XPath parser context with the compiled expression
14271 *
14272 * Evaluate the Precompiled Streamable XPath expression in the given context.
14273 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014274static int
14275xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14276 xmlXPathObjectPtr *resultSeq, int toBool)
14277{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014278 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014279 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014280 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014281 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014282 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014283 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014284
14285 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014286
14287 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014288 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014289 max_depth = xmlPatternMaxDepth(comp);
14290 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014291 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014292 if (max_depth == -2)
14293 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014294 min_depth = xmlPatternMinDepth(comp);
14295 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014296 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014297 from_root = xmlPatternFromRoot(comp);
14298 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014299 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014300#if 0
14301 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14302#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014303
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014304 if (! toBool) {
14305 if (resultSeq == NULL)
14306 return(-1);
14307 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14308 if (*resultSeq == NULL)
14309 return(-1);
14310 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014311
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014312 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014313 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014314 */
14315 if (min_depth == 0) {
14316 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014317 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014318 if (toBool)
14319 return(1);
14320 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014321 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014322 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014323 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014324 if (toBool)
14325 return(1);
14326 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014327 }
14328 }
14329 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014330 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014331 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014332
Daniel Veillard56de87e2005-02-16 00:22:29 +000014333 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014334 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014335 } else if (ctxt->node != NULL) {
14336 switch (ctxt->node->type) {
14337 case XML_ELEMENT_NODE:
14338 case XML_DOCUMENT_NODE:
14339 case XML_DOCUMENT_FRAG_NODE:
14340 case XML_HTML_DOCUMENT_NODE:
14341#ifdef LIBXML_DOCB_ENABLED
14342 case XML_DOCB_DOCUMENT_NODE:
14343#endif
14344 cur = ctxt->node;
14345 break;
14346 case XML_ATTRIBUTE_NODE:
14347 case XML_TEXT_NODE:
14348 case XML_CDATA_SECTION_NODE:
14349 case XML_ENTITY_REF_NODE:
14350 case XML_ENTITY_NODE:
14351 case XML_PI_NODE:
14352 case XML_COMMENT_NODE:
14353 case XML_NOTATION_NODE:
14354 case XML_DTD_NODE:
14355 case XML_DOCUMENT_TYPE_NODE:
14356 case XML_ELEMENT_DECL:
14357 case XML_ATTRIBUTE_DECL:
14358 case XML_ENTITY_DECL:
14359 case XML_NAMESPACE_DECL:
14360 case XML_XINCLUDE_START:
14361 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014362 break;
14363 }
14364 limit = cur;
14365 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014366 if (cur == NULL) {
14367 return(0);
14368 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014369
14370 patstream = xmlPatternGetStreamCtxt(comp);
14371 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014372 /*
14373 * QUESTION TODO: Is this an error?
14374 */
14375 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014376 }
14377
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014378 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014379
Daniel Veillard56de87e2005-02-16 00:22:29 +000014380 if (from_root) {
14381 ret = xmlStreamPush(patstream, NULL, NULL);
14382 if (ret < 0) {
14383 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014384 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014385 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014386 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014387 }
14388 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014389 depth = 0;
14390 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014391next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014392 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014393 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014394
14395 switch (cur->type) {
14396 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014397 case XML_TEXT_NODE:
14398 case XML_CDATA_SECTION_NODE:
14399 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014400 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014401 if (cur->type == XML_ELEMENT_NODE) {
14402 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014403 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014404 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014405 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14406 else
14407 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014408
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014409 if (ret < 0) {
14410 /* NOP. */
14411 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014412 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014413 goto return_1;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014414 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14415 < 0) {
14416 ctxt->lastError.domain = XML_FROM_XPATH;
14417 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14418 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014419 }
14420 if ((cur->children == NULL) || (depth >= max_depth)) {
14421 ret = xmlStreamPop(patstream);
14422 while (cur->next != NULL) {
14423 cur = cur->next;
14424 if ((cur->type != XML_ENTITY_DECL) &&
14425 (cur->type != XML_DTD_NODE))
14426 goto next_node;
14427 }
14428 }
14429 default:
14430 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014431 }
14432
Daniel Veillard56de87e2005-02-16 00:22:29 +000014433scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080014434 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014435 if ((cur->children != NULL) && (depth < max_depth)) {
14436 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014437 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014438 */
14439 if (cur->children->type != XML_ENTITY_DECL) {
14440 cur = cur->children;
14441 depth++;
14442 /*
14443 * Skip DTDs
14444 */
14445 if (cur->type != XML_DTD_NODE)
14446 continue;
14447 }
14448 }
14449
14450 if (cur == limit)
14451 break;
14452
14453 while (cur->next != NULL) {
14454 cur = cur->next;
14455 if ((cur->type != XML_ENTITY_DECL) &&
14456 (cur->type != XML_DTD_NODE))
14457 goto next_node;
14458 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014459
Daniel Veillard56de87e2005-02-16 00:22:29 +000014460 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014461 cur = cur->parent;
14462 depth--;
14463 if ((cur == NULL) || (cur == limit))
14464 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014465 if (cur->type == XML_ELEMENT_NODE) {
14466 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014467 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014468 ((cur->type == XML_TEXT_NODE) ||
14469 (cur->type == XML_CDATA_SECTION_NODE) ||
14470 (cur->type == XML_COMMENT_NODE) ||
14471 (cur->type == XML_PI_NODE)))
14472 {
14473 ret = xmlStreamPop(patstream);
14474 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014475 if (cur->next != NULL) {
14476 cur = cur->next;
14477 break;
14478 }
14479 } while (cur != NULL);
14480
14481 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014482
Daniel Veillard56de87e2005-02-16 00:22:29 +000014483done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014484
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014485#if 0
14486 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014487 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014488#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014489
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014490 if (patstream)
14491 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014492 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014493
14494return_1:
14495 if (patstream)
14496 xmlFreeStreamCtxt(patstream);
14497 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014498}
14499#endif /* XPATH_STREAMING */
14500
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014501/**
14502 * xmlXPathRunEval:
14503 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014504 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014505 *
14506 * Evaluate the Precompiled XPath expression in the given context.
14507 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014508static int
14509xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14510{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014511 xmlXPathCompExprPtr comp;
14512
14513 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014514 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014515
14516 if (ctxt->valueTab == NULL) {
14517 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014518 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014519 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14520 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014521 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014522 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014523 }
14524 ctxt->valueNr = 0;
14525 ctxt->valueMax = 10;
14526 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014527 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014528 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014529#ifdef XPATH_STREAMING
14530 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014531 int res;
14532
14533 if (toBool) {
14534 /*
14535 * Evaluation to boolean result.
14536 */
14537 res = xmlXPathRunStreamEval(ctxt->context,
14538 ctxt->comp->stream, NULL, 1);
14539 if (res != -1)
14540 return(res);
14541 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014542 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014543
14544 /*
14545 * Evaluation to a sequence.
14546 */
14547 res = xmlXPathRunStreamEval(ctxt->context,
14548 ctxt->comp->stream, &resObj, 0);
14549
14550 if ((res != -1) && (resObj != NULL)) {
14551 valuePush(ctxt, resObj);
14552 return(0);
14553 }
14554 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014555 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014556 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014557 /*
14558 * QUESTION TODO: This falls back to normal XPath evaluation
14559 * if res == -1. Is this intended?
14560 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014561 }
14562#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014563 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014564 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014565 xmlGenericError(xmlGenericErrorContext,
14566 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014567 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014568 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014569 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014570 return(xmlXPathCompOpEvalToBoolean(ctxt,
14571 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014572 else
14573 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14574
14575 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014576}
14577
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014578/************************************************************************
14579 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014580 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014581 * *
14582 ************************************************************************/
14583
14584/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014585 * xmlXPathEvalPredicate:
14586 * @ctxt: the XPath context
14587 * @res: the Predicate Expression evaluation result
14588 *
14589 * Evaluate a predicate result for the current node.
14590 * A PredicateExpr is evaluated by evaluating the Expr and converting
14591 * the result to a boolean. If the result is a number, the result will
14592 * be converted to true if the number is equal to the position of the
14593 * context node in the context node list (as returned by the position
14594 * function) and will be converted to false otherwise; if the result
14595 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014596 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014597 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014598 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014599 */
14600int
14601xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014602 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014603 switch (res->type) {
14604 case XPATH_BOOLEAN:
14605 return(res->boolval);
14606 case XPATH_NUMBER:
14607 return(res->floatval == ctxt->proximityPosition);
14608 case XPATH_NODESET:
14609 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014610 if (res->nodesetval == NULL)
14611 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014612 return(res->nodesetval->nodeNr != 0);
14613 case XPATH_STRING:
14614 return((res->stringval != NULL) &&
14615 (xmlStrlen(res->stringval) != 0));
14616 default:
14617 STRANGE
14618 }
14619 return(0);
14620}
14621
14622/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014623 * xmlXPathEvaluatePredicateResult:
14624 * @ctxt: the XPath Parser context
14625 * @res: the Predicate Expression evaluation result
14626 *
14627 * Evaluate a predicate result for the current node.
14628 * A PredicateExpr is evaluated by evaluating the Expr and converting
14629 * the result to a boolean. If the result is a number, the result will
14630 * be converted to true if the number is equal to the position of the
14631 * context node in the context node list (as returned by the position
14632 * function) and will be converted to false otherwise; if the result
14633 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014634 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014635 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014636 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014637 */
14638int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014639xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014640 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014641 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014642 switch (res->type) {
14643 case XPATH_BOOLEAN:
14644 return(res->boolval);
14645 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014646#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014647 return((res->floatval == ctxt->context->proximityPosition) &&
14648 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014649#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014650 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014651#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014652 case XPATH_NODESET:
14653 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014654 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014655 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014656 return(res->nodesetval->nodeNr != 0);
14657 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014658 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014659#ifdef LIBXML_XPTR_ENABLED
14660 case XPATH_LOCATIONSET:{
14661 xmlLocationSetPtr ptr = res->user;
14662 if (ptr == NULL)
14663 return(0);
14664 return (ptr->locNr != 0);
14665 }
14666#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014667 default:
14668 STRANGE
14669 }
14670 return(0);
14671}
14672
Daniel Veillard56de87e2005-02-16 00:22:29 +000014673#ifdef XPATH_STREAMING
14674/**
14675 * xmlXPathTryStreamCompile:
14676 * @ctxt: an XPath context
14677 * @str: the XPath expression
14678 *
14679 * Try to compile the XPath expression as a streamable subset.
14680 *
14681 * Returns the compiled expression or NULL if failed to compile.
14682 */
14683static xmlXPathCompExprPtr
14684xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14685 /*
14686 * Optimization: use streaming patterns when the XPath expression can
14687 * be compiled to a stream lookup
14688 */
14689 xmlPatternPtr stream;
14690 xmlXPathCompExprPtr comp;
14691 xmlDictPtr dict = NULL;
14692 const xmlChar **namespaces = NULL;
14693 xmlNsPtr ns;
14694 int i, j;
14695
14696 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14697 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014698 const xmlChar *tmp;
14699
14700 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014701 * We don't try to handle expressions using the verbose axis
14702 * specifiers ("::"), just the simplied form at this point.
14703 * Additionally, if there is no list of namespaces available and
14704 * there's a ":" in the expression, indicating a prefixed QName,
14705 * then we won't try to compile either. xmlPatterncompile() needs
14706 * to have a list of namespaces at compilation time in order to
14707 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014708 */
14709 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014710 if ((tmp != NULL) &&
14711 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014712 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014713
Daniel Veillard56de87e2005-02-16 00:22:29 +000014714 if (ctxt != NULL) {
14715 dict = ctxt->dict;
14716 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014717 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014718 if (namespaces == NULL) {
14719 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14720 return(NULL);
14721 }
14722 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14723 ns = ctxt->namespaces[j];
14724 namespaces[i++] = ns->href;
14725 namespaces[i++] = ns->prefix;
14726 }
14727 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014728 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014729 }
14730 }
14731
William M. Brackea152c02005-06-09 18:12:28 +000014732 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14733 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014734 if (namespaces != NULL) {
14735 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014736 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014737 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14738 comp = xmlXPathNewCompExpr();
14739 if (comp == NULL) {
14740 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14741 return(NULL);
14742 }
14743 comp->stream = stream;
14744 comp->dict = dict;
14745 if (comp->dict)
14746 xmlDictReference(comp->dict);
14747 return(comp);
14748 }
14749 xmlFreePattern(stream);
14750 }
14751 return(NULL);
14752}
14753#endif /* XPATH_STREAMING */
14754
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014755static void
Nick Wellnhofer62270532012-08-19 19:42:38 +020014756xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014757{
14758 /*
14759 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14760 * internal representation.
14761 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014762
Nick Wellnhoferb4bcba22013-08-05 00:15:11 +020014763 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14764 (op->ch1 != -1) &&
14765 (op->ch2 == -1 /* no predicate */))
Nick Wellnhofer62270532012-08-19 19:42:38 +020014766 {
14767 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14768
14769 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14770 ((xmlXPathAxisVal) prevop->value ==
14771 AXIS_DESCENDANT_OR_SELF) &&
14772 (prevop->ch2 == -1) &&
14773 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14774 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14775 {
14776 /*
14777 * This is a "descendant-or-self::node()" without predicates.
14778 * Try to eliminate it.
14779 */
14780
14781 switch ((xmlXPathAxisVal) op->value) {
14782 case AXIS_CHILD:
14783 case AXIS_DESCENDANT:
14784 /*
14785 * Convert "descendant-or-self::node()/child::" or
14786 * "descendant-or-self::node()/descendant::" to
14787 * "descendant::"
14788 */
14789 op->ch1 = prevop->ch1;
14790 op->value = AXIS_DESCENDANT;
14791 break;
14792 case AXIS_SELF:
14793 case AXIS_DESCENDANT_OR_SELF:
14794 /*
14795 * Convert "descendant-or-self::node()/self::" or
14796 * "descendant-or-self::node()/descendant-or-self::" to
14797 * to "descendant-or-self::"
14798 */
14799 op->ch1 = prevop->ch1;
14800 op->value = AXIS_DESCENDANT_OR_SELF;
14801 break;
14802 default:
14803 break;
14804 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014805 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014806 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014807
Xin Li28c53d32017-03-07 00:33:02 +000014808 /* OP_VALUE has invalid ch1. */
14809 if (op->op == XPATH_OP_VALUE)
14810 return;
14811
Nick Wellnhofer62270532012-08-19 19:42:38 +020014812 /* Recurse */
14813 if (op->ch1 != -1)
14814 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014815 if (op->ch2 != -1)
Nick Wellnhofer62270532012-08-19 19:42:38 +020014816 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014817}
14818
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014819/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014820 * xmlXPathCtxtCompile:
14821 * @ctxt: an XPath context
14822 * @str: the XPath expression
14823 *
14824 * Compile an XPath expression
14825 *
14826 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14827 * the caller has to free the object.
14828 */
14829xmlXPathCompExprPtr
14830xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14831 xmlXPathParserContextPtr pctxt;
14832 xmlXPathCompExprPtr comp;
14833
Daniel Veillard56de87e2005-02-16 00:22:29 +000014834#ifdef XPATH_STREAMING
14835 comp = xmlXPathTryStreamCompile(ctxt, str);
14836 if (comp != NULL)
14837 return(comp);
14838#endif
14839
Daniel Veillard4773df22004-01-23 13:15:13 +000014840 xmlXPathInit();
14841
14842 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014843 if (pctxt == NULL)
14844 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014845 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014846
14847 if( pctxt->error != XPATH_EXPRESSION_OK )
14848 {
14849 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014850 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014851 }
14852
14853 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014854 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014855 * aleksey: in some cases this line prints *second* error message
14856 * (see bug #78858) and probably this should be fixed.
14857 * However, we are not sure that all error messages are printed
14858 * out in other places. It's not critical so we leave it as-is for now
14859 */
14860 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14861 comp = NULL;
14862 } else {
14863 comp = pctxt->comp;
14864 pctxt->comp = NULL;
14865 }
14866 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014867
Daniel Veillard4773df22004-01-23 13:15:13 +000014868 if (comp != NULL) {
14869 comp->expr = xmlStrdup(str);
14870#ifdef DEBUG_EVAL_COUNTS
14871 comp->string = xmlStrdup(str);
14872 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014873#endif
Nick Wellnhofer62270532012-08-19 19:42:38 +020014874 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14875 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014876 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014877 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014878 return(comp);
14879}
14880
14881/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014882 * xmlXPathCompile:
14883 * @str: the XPath expression
14884 *
14885 * Compile an XPath expression
14886 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014887 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014888 * the caller has to free the object.
14889 */
14890xmlXPathCompExprPtr
14891xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014892 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014893}
14894
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014895/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014896 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014897 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014898 * @ctxt: the XPath context
14899 * @resObj: the resulting XPath object or NULL
14900 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014901 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014902 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014903 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014904 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014905 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014906 * the caller has to free the object.
14907 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014908static int
14909xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14910 xmlXPathContextPtr ctxt,
14911 xmlXPathObjectPtr *resObj,
14912 int toBool)
14913{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014914 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014915#ifndef LIBXML_THREAD_ENABLED
14916 static int reentance = 0;
14917#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014918 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014919
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014920 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014921
14922 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014923 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014924 xmlXPathInit();
14925
Daniel Veillard81463942001-10-16 12:34:39 +000014926#ifndef LIBXML_THREAD_ENABLED
14927 reentance++;
14928 if (reentance > 1)
14929 xmlXPathDisableOptimizer = 1;
14930#endif
14931
Daniel Veillardf06307e2001-07-03 10:35:50 +000014932#ifdef DEBUG_EVAL_COUNTS
14933 comp->nb++;
14934 if ((comp->string != NULL) && (comp->nb > 100)) {
14935 fprintf(stderr, "100 x %s\n", comp->string);
14936 comp->nb = 0;
14937 }
14938#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014939 pctxt = xmlXPathCompParserContext(comp, ctxt);
14940 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014941
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014942 if (resObj) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014943 if (pctxt->value == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014944 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014945 "xmlXPathCompiledEval: evaluation failed\n");
Daniel Veillard45490ae2008-07-29 09:13:19 +000014946 *resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014947 } else {
14948 *resObj = valuePop(pctxt);
14949 }
Owen Taylor3473f882001-02-23 17:55:21 +000014950 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014951
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014952 /*
14953 * Pop all remaining objects from the stack.
14954 */
14955 if (pctxt->valueNr > 0) {
14956 xmlXPathObjectPtr tmp;
14957 int stack = 0;
14958
14959 do {
14960 tmp = valuePop(pctxt);
14961 if (tmp != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014962 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014963 xmlXPathReleaseObject(ctxt, tmp);
14964 }
14965 } while (tmp != NULL);
14966 if ((stack != 0) &&
14967 ((toBool) || ((resObj) && (*resObj))))
14968 {
14969 xmlGenericError(xmlGenericErrorContext,
14970 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14971 stack);
14972 }
Owen Taylor3473f882001-02-23 17:55:21 +000014973 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014974
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014975 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14976 xmlXPathFreeObject(*resObj);
14977 *resObj = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014978 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014979 pctxt->comp = NULL;
14980 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014981#ifndef LIBXML_THREAD_ENABLED
14982 reentance--;
14983#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014984
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014985 return(res);
14986}
14987
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014988/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014989 * xmlXPathCompiledEval:
14990 * @comp: the compiled XPath expression
14991 * @ctx: the XPath context
14992 *
14993 * Evaluate the Precompiled XPath expression in the given context.
14994 *
14995 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14996 * the caller has to free the object.
14997 */
14998xmlXPathObjectPtr
14999xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
15000{
15001 xmlXPathObjectPtr res = NULL;
15002
15003 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
15004 return(res);
15005}
15006
15007/**
15008 * xmlXPathCompiledEvalToBoolean:
15009 * @comp: the compiled XPath expression
15010 * @ctxt: the XPath context
15011 *
15012 * Applies the XPath boolean() function on the result of the given
15013 * compiled expression.
15014 *
15015 * Returns 1 if the expression evaluated to true, 0 if to false and
15016 * -1 in API and internal errors.
15017 */
15018int
15019xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
15020 xmlXPathContextPtr ctxt)
15021{
15022 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
15023}
15024
15025/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000015026 * xmlXPathEvalExpr:
15027 * @ctxt: the XPath Parser context
15028 *
15029 * Parse and evaluate an XPath expression in the given context,
15030 * then push the result on the context stack
15031 */
15032void
15033xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000015034#ifdef XPATH_STREAMING
15035 xmlXPathCompExprPtr comp;
15036#endif
15037
Daniel Veillarda82b1822004-11-08 16:24:57 +000015038 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015039
Daniel Veillard56de87e2005-02-16 00:22:29 +000015040#ifdef XPATH_STREAMING
15041 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15042 if (comp != NULL) {
15043 if (ctxt->comp != NULL)
15044 xmlXPathFreeCompExpr(ctxt->comp);
15045 ctxt->comp = comp;
15046 if (ctxt->cur != NULL)
15047 while (*ctxt->cur != 0) ctxt->cur++;
15048 } else
15049#endif
15050 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000015051 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000015052 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
15053 (ctxt->comp != NULL) &&
Nick Wellnhofer62270532012-08-19 19:42:38 +020015054 (ctxt->comp->nbStep > 1) &&
15055 (ctxt->comp->last >= 0))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000015056 {
Nick Wellnhofer62270532012-08-19 19:42:38 +020015057 xmlXPathOptimizeExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000015058 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000015059 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000015060 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000015061 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015062 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000015063}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015064
15065/**
15066 * xmlXPathEval:
15067 * @str: the XPath expression
15068 * @ctx: the XPath context
15069 *
15070 * Evaluate the XPath Location Path in the given context.
15071 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000015072 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015073 * the caller has to free the object.
15074 */
15075xmlXPathObjectPtr
15076xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15077 xmlXPathParserContextPtr ctxt;
15078 xmlXPathObjectPtr res, tmp, init = NULL;
15079 int stack = 0;
15080
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
15090 if (ctxt->value == NULL) {
15091 xmlGenericError(xmlGenericErrorContext,
15092 "xmlXPathEval: evaluation failed\n");
15093 res = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015094 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
Daniel Veillard56de87e2005-02-16 00:22:29 +000015095#ifdef XPATH_STREAMING
15096 && (ctxt->comp->stream == NULL)
15097#endif
15098 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015099 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15100 res = NULL;
15101 } else {
15102 res = valuePop(ctxt);
15103 }
15104
15105 do {
15106 tmp = valuePop(ctxt);
15107 if (tmp != NULL) {
15108 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015109 stack++;
15110 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015111 }
15112 } while (tmp != NULL);
15113 if ((stack != 0) && (res != NULL)) {
15114 xmlGenericError(xmlGenericErrorContext,
15115 "xmlXPathEval: %d object left on the stack\n",
15116 stack);
15117 }
15118 if (ctxt->error != XPATH_EXPRESSION_OK) {
15119 xmlXPathFreeObject(res);
15120 res = NULL;
15121 }
15122
Owen Taylor3473f882001-02-23 17:55:21 +000015123 xmlXPathFreeParserContext(ctxt);
15124 return(res);
15125}
15126
15127/**
Alex Bligh28876af2013-03-23 17:23:27 +000015128 * xmlXPathSetContextNode:
15129 * @node: the node to to use as the context node
15130 * @ctx: the XPath context
15131 *
15132 * Sets 'node' as the context node. The node must be in the same
15133 * document as that associated with the context.
15134 *
15135 * Returns -1 in case of error or 0 if successful
15136 */
15137int
15138xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15139 if ((node == NULL) || (ctx == NULL))
15140 return(-1);
15141
15142 if (node->doc == ctx->doc) {
15143 ctx->node = node;
15144 return(0);
15145 }
15146 return(-1);
15147}
15148
15149/**
15150 * xmlXPathNodeEval:
15151 * @node: the node to to use as the context node
15152 * @str: the XPath expression
15153 * @ctx: the XPath context
15154 *
15155 * Evaluate the XPath Location Path in the given context. The node 'node'
15156 * is set as the context node. The context node is not restored.
15157 *
15158 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15159 * the caller has to free the object.
15160 */
15161xmlXPathObjectPtr
15162xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15163 if (str == NULL)
15164 return(NULL);
15165 if (xmlXPathSetContextNode(node, ctx) < 0)
15166 return(NULL);
15167 return(xmlXPathEval(str, ctx));
15168}
15169
15170/**
Owen Taylor3473f882001-02-23 17:55:21 +000015171 * xmlXPathEvalExpression:
15172 * @str: the XPath expression
15173 * @ctxt: the XPath context
15174 *
15175 * Evaluate the XPath expression in the given context.
15176 *
15177 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15178 * the caller has to free the object.
15179 */
15180xmlXPathObjectPtr
15181xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15182 xmlXPathParserContextPtr pctxt;
15183 xmlXPathObjectPtr res, tmp;
15184 int stack = 0;
15185
William M. Brackf13f77f2004-11-12 16:03:48 +000015186 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000015187
William M. Brackf13f77f2004-11-12 16:03:48 +000015188 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000015189
15190 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000015191 if (pctxt == NULL)
15192 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000015193 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000015194
Daniel Veillardc465ffc2006-10-17 19:39:33 +000015195 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000015196 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15197 res = NULL;
15198 } else {
15199 res = valuePop(pctxt);
15200 }
15201 do {
15202 tmp = valuePop(pctxt);
15203 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015204 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000015205 stack++;
15206 }
15207 } while (tmp != NULL);
15208 if ((stack != 0) && (res != NULL)) {
15209 xmlGenericError(xmlGenericErrorContext,
15210 "xmlXPathEvalExpression: %d object left on the stack\n",
15211 stack);
15212 }
15213 xmlXPathFreeParserContext(pctxt);
15214 return(res);
15215}
15216
Daniel Veillard42766c02002-08-22 20:52:17 +000015217/************************************************************************
15218 * *
15219 * Extra functions not pertaining to the XPath spec *
15220 * *
15221 ************************************************************************/
15222/**
15223 * xmlXPathEscapeUriFunction:
15224 * @ctxt: the XPath Parser context
15225 * @nargs: the number of arguments
15226 *
15227 * Implement the escape-uri() XPath function
15228 * string escape-uri(string $str, bool $escape-reserved)
15229 *
15230 * This function applies the URI escaping rules defined in section 2 of [RFC
15231 * 2396] to the string supplied as $uri-part, which typically represents all
15232 * or part of a URI. The effect of the function is to replace any special
15233 * character in the string by an escape sequence of the form %xx%yy...,
15234 * where xxyy... is the hexadecimal representation of the octets used to
15235 * represent the character in UTF-8.
15236 *
15237 * The set of characters that are escaped depends on the setting of the
15238 * boolean argument $escape-reserved.
15239 *
15240 * If $escape-reserved is true, all characters are escaped other than lower
15241 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15242 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15243 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15244 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15245 * A-F).
15246 *
15247 * If $escape-reserved is false, the behavior differs in that characters
15248 * referred to in [RFC 2396] as reserved characters are not escaped. These
15249 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015250 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015251 * [RFC 2396] does not define whether escaped URIs should use lower case or
15252 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15253 * compared using string comparison functions, this function must always use
15254 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015255 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015256 * Generally, $escape-reserved should be set to true when escaping a string
15257 * that is to form a single part of a URI, and to false when escaping an
15258 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015259 *
15260 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015261 * utf-8 and then converted according to RFC 2396.
15262 *
15263 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015264 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015265 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15266 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15267 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15268 *
15269 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015270static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015271xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15272 xmlXPathObjectPtr str;
15273 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080015274 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000015275 xmlChar *cptr;
15276 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015277
Daniel Veillard42766c02002-08-22 20:52:17 +000015278 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015279
Daniel Veillard42766c02002-08-22 20:52:17 +000015280 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015281
Daniel Veillard42766c02002-08-22 20:52:17 +000015282 CAST_TO_STRING;
15283 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015284
Daniel Veillardade10f22012-07-12 09:43:27 +080015285 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015286
Daniel Veillard42766c02002-08-22 20:52:17 +000015287 escape[0] = '%';
15288 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015289
Daniel Veillard42766c02002-08-22 20:52:17 +000015290 if (target) {
15291 for (cptr = str->stringval; *cptr; cptr++) {
15292 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15293 (*cptr >= 'a' && *cptr <= 'z') ||
15294 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015295 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015296 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15297 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015298 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015299 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15300 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15301 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15302 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15303 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15304 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15305 (!escape_reserved &&
15306 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15307 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15308 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15309 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080015310 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000015311 } else {
15312 if ((*cptr >> 4) < 10)
15313 escape[1] = '0' + (*cptr >> 4);
15314 else
15315 escape[1] = 'A' - 10 + (*cptr >> 4);
15316 if ((*cptr & 0xF) < 10)
15317 escape[2] = '0' + (*cptr & 0xF);
15318 else
15319 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015320
Daniel Veillardade10f22012-07-12 09:43:27 +080015321 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000015322 }
15323 }
15324 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015325 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080015326 xmlBufContent(target)));
15327 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015328 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015329}
15330
Owen Taylor3473f882001-02-23 17:55:21 +000015331/**
15332 * xmlXPathRegisterAllFunctions:
15333 * @ctxt: the XPath context
15334 *
15335 * Registers all default XPath functions in this context
15336 */
15337void
15338xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15339{
15340 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15341 xmlXPathBooleanFunction);
15342 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15343 xmlXPathCeilingFunction);
15344 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15345 xmlXPathCountFunction);
15346 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15347 xmlXPathConcatFunction);
15348 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15349 xmlXPathContainsFunction);
15350 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15351 xmlXPathIdFunction);
15352 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15353 xmlXPathFalseFunction);
15354 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15355 xmlXPathFloorFunction);
15356 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15357 xmlXPathLastFunction);
15358 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15359 xmlXPathLangFunction);
15360 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15361 xmlXPathLocalNameFunction);
15362 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15363 xmlXPathNotFunction);
15364 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15365 xmlXPathNameFunction);
15366 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15367 xmlXPathNamespaceURIFunction);
15368 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15369 xmlXPathNormalizeFunction);
15370 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15371 xmlXPathNumberFunction);
15372 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15373 xmlXPathPositionFunction);
15374 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15375 xmlXPathRoundFunction);
15376 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15377 xmlXPathStringFunction);
15378 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15379 xmlXPathStringLengthFunction);
15380 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15381 xmlXPathStartsWithFunction);
15382 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15383 xmlXPathSubstringFunction);
15384 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15385 xmlXPathSubstringBeforeFunction);
15386 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15387 xmlXPathSubstringAfterFunction);
15388 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15389 xmlXPathSumFunction);
15390 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15391 xmlXPathTrueFunction);
15392 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15393 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015394
15395 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15396 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15397 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015398}
15399
15400#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015401#define bottom_xpath
15402#include "elfgcchack.h"