blob: 2bb6d3445505063d16a895a3ab73bef9cecaea7d [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
Vojtech Fried3e031b72012-08-24 16:52:44 +0800138/*
139 * Wrapper for the Timsort argorithm from timsort.h
140 */
141#ifdef WITH_TIM_SORT
142#define SORT_NAME libxml_domnode
143#define SORT_TYPE xmlNodePtr
144/**
145 * wrap_cmp:
146 * @x: a node
147 * @y: another node
148 *
149 * Comparison function for the Timsort implementation
150 *
Daniel Veillard510e7582012-09-04 11:50:36 +0800151 * Returns -2 in case of error -1 if first point < second point, 0 if
152 * it's the same node, +1 otherwise
Vojtech Fried3e031b72012-08-24 16:52:44 +0800153 */
154static
155int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
156#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
157 static int xmlXPathCmpNodesExt(xmlNodePtr, xmlNodePtr);
158 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
159 {
160 int res = xmlXPathCmpNodesExt(x, y);
161 return res == -2 ? res : -res;
162 }
163#else
164 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
165 {
166 int res = xmlXPathCmpNodes(x, y);
167 return res == -2 ? res : -res;
168 }
169#endif
170#define SORT_CMP(x, y) (wrap_cmp(x, y))
171#include "timsort.h"
172#endif /* WITH_TIM_SORT */
173
William M. Brack21e4ef22005-01-02 09:53:13 +0000174#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000175
176/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000177 * *
178 * Floating point stuff *
179 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000180 ************************************************************************/
181
Daniel Veillardc0631a62001-09-20 13:56:06 +0000182#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000183#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000184#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000185#include "trionan.c"
186
Owen Taylor3473f882001-02-23 17:55:21 +0000187/*
Owen Taylor3473f882001-02-23 17:55:21 +0000188 * The lack of portability of this section of the libc is annoying !
189 */
190double xmlXPathNAN = 0;
191double xmlXPathPINF = 1;
192double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000193static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000194static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000195
Owen Taylor3473f882001-02-23 17:55:21 +0000196/**
197 * xmlXPathInit:
198 *
199 * Initialize the XPath environment
200 */
201void
202xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000203 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000204
Bjorn Reese45029602001-08-21 09:23:53 +0000205 xmlXPathPINF = trio_pinf();
206 xmlXPathNINF = trio_ninf();
207 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000208 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000209
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000210 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000211}
212
Daniel Veillardcda96922001-08-21 10:56:31 +0000213/**
214 * xmlXPathIsNaN:
215 * @val: a double value
216 *
217 * Provides a portable isnan() function to detect whether a double
218 * is a NotaNumber. Based on trio code
219 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000220 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000221 * Returns 1 if the value is a NaN, 0 otherwise
222 */
223int
224xmlXPathIsNaN(double val) {
225 return(trio_isnan(val));
226}
227
228/**
229 * xmlXPathIsInf:
230 * @val: a double value
231 *
232 * Provides a portable isinf() function to detect whether a double
233 * is a +Infinite or -Infinite. Based on trio code
234 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000235 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000236 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
237 */
238int
239xmlXPathIsInf(double val) {
240 return(trio_isinf(val));
241}
242
Daniel Veillard4432df22003-09-28 18:58:27 +0000243#endif /* SCHEMAS or XPATH */
244#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000245/**
246 * xmlXPathGetSign:
247 * @val: a double value
248 *
249 * Provides a portable function to detect the sign of a double
250 * Modified from trio code
251 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000252 *
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000253 * Returns 1 if the value is Negative, 0 if positive
254 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000255static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000256xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000257 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000258}
259
260
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000261/*
262 * TODO: when compatibility allows remove all "fake node libxslt" strings
263 * the test should just be name[0] = ' '
264 */
Daniel Veillard074f37e2008-09-01 13:38:22 +0000265#ifdef DEBUG_XPATH_EXPRESSION
266#define DEBUG_STEP
267#define DEBUG_EXPR
268#define DEBUG_EVAL_COUNTS
269#endif
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000270
271static xmlNs xmlXPathXMLNamespaceStruct = {
272 NULL,
273 XML_NAMESPACE_DECL,
274 XML_XML_NAMESPACE,
275 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000276 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000277 NULL
278};
279static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
280#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard45490ae2008-07-29 09:13:19 +0000281/*
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000282 * Optimizer is disabled only when threaded apps are detected while
283 * the library ain't compiled for thread safety.
284 */
285static int xmlXPathDisableOptimizer = 0;
286#endif
287
Owen Taylor3473f882001-02-23 17:55:21 +0000288/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000289 * *
290 * Error handling routines *
291 * *
292 ************************************************************************/
293
Daniel Veillard24505b02005-07-28 23:49:35 +0000294/**
295 * XP_ERRORNULL:
296 * @X: the error code
297 *
298 * Macro to raise an XPath error and return NULL.
299 */
300#define XP_ERRORNULL(X) \
301 { xmlXPathErr(ctxt, X); return(NULL); }
302
William M. Brack08171912003-12-29 02:52:11 +0000303/*
304 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
305 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000306static const char *xmlXPathErrorMessages[] = {
307 "Ok\n",
308 "Number encoding\n",
309 "Unfinished literal\n",
310 "Start of literal\n",
311 "Expected $ for variable reference\n",
312 "Undefined variable\n",
313 "Invalid predicate\n",
314 "Invalid expression\n",
315 "Missing closing curly brace\n",
316 "Unregistered function\n",
317 "Invalid operand\n",
318 "Invalid type\n",
319 "Invalid number of arguments\n",
320 "Invalid context size\n",
321 "Invalid context position\n",
322 "Memory allocation error\n",
323 "Syntax error\n",
324 "Resource error\n",
325 "Sub resource error\n",
326 "Undefined namespace prefix\n",
327 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000328 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000329 "Invalid or incomplete context\n",
Daniel Veillardf5048b32011-08-18 17:10:13 +0800330 "Stack usage errror\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000331 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000332};
William M. Brackcd65bc92005-01-06 09:39:18 +0000333#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
334 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000335/**
336 * xmlXPathErrMemory:
337 * @ctxt: an XPath context
338 * @extra: extra informations
339 *
340 * Handle a redefinition of attribute error
341 */
342static void
343xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
344{
345 if (ctxt != NULL) {
346 if (extra) {
347 xmlChar buf[200];
348
349 xmlStrPrintf(buf, 200,
350 BAD_CAST "Memory allocation failed : %s\n",
351 extra);
352 ctxt->lastError.message = (char *) xmlStrdup(buf);
353 } else {
354 ctxt->lastError.message = (char *)
355 xmlStrdup(BAD_CAST "Memory allocation failed\n");
356 }
357 ctxt->lastError.domain = XML_FROM_XPATH;
358 ctxt->lastError.code = XML_ERR_NO_MEMORY;
359 if (ctxt->error != NULL)
360 ctxt->error(ctxt->userData, &ctxt->lastError);
361 } else {
362 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000363 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000364 NULL, NULL, XML_FROM_XPATH,
365 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
366 extra, NULL, NULL, 0, 0,
367 "Memory allocation failed : %s\n", extra);
368 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000369 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000370 NULL, NULL, XML_FROM_XPATH,
371 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
372 NULL, NULL, NULL, 0, 0,
373 "Memory allocation failed\n");
374 }
375}
376
377/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000378 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000379 * @ctxt: an XPath parser context
380 * @extra: extra informations
381 *
382 * Handle a redefinition of attribute error
383 */
384static void
385xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
386{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000387 if (ctxt == NULL)
388 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000389 else {
390 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000391 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000392 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000393}
394
395/**
396 * xmlXPathErr:
397 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000398 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000399 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000400 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000401 */
402void
403xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
404{
William M. Brackcd65bc92005-01-06 09:39:18 +0000405 if ((error < 0) || (error > MAXERRNO))
406 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000407 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000408 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000409 NULL, NULL, XML_FROM_XPATH,
410 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
411 XML_ERR_ERROR, NULL, 0,
412 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200413 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000414 return;
415 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000416 ctxt->error = error;
417 if (ctxt->context == NULL) {
418 __xmlRaiseError(NULL, NULL, NULL,
419 NULL, NULL, XML_FROM_XPATH,
420 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
421 XML_ERR_ERROR, NULL, 0,
422 (const char *) ctxt->base, NULL, NULL,
423 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200424 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000425 return;
426 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000427
428 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000429 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000430
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000431 ctxt->context->lastError.domain = XML_FROM_XPATH;
432 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
433 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000434 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000435 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
436 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
437 ctxt->context->lastError.node = ctxt->context->debugNode;
438 if (ctxt->context->error != NULL) {
439 ctxt->context->error(ctxt->context->userData,
440 &ctxt->context->lastError);
441 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000442 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000443 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
444 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
445 XML_ERR_ERROR, NULL, 0,
446 (const char *) ctxt->base, NULL, NULL,
447 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200448 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000449 }
450
451}
452
453/**
454 * xmlXPatherror:
455 * @ctxt: the XPath Parser context
456 * @file: the file name
457 * @line: the line number
458 * @no: the error number
459 *
460 * Formats an error message.
461 */
462void
463xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
464 int line ATTRIBUTE_UNUSED, int no) {
465 xmlXPathErr(ctxt, no);
466}
467
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000468/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000469 * *
470 * Utilities *
471 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000472 ************************************************************************/
473
474/**
475 * xsltPointerList:
476 *
477 * Pointer-list for various purposes.
478 */
479typedef struct _xmlPointerList xmlPointerList;
480typedef xmlPointerList *xmlPointerListPtr;
481struct _xmlPointerList {
482 void **items;
483 int number;
484 int size;
485};
486/*
487* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
488* and here, we should make the functions public.
489*/
490static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000491xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000492 void *item,
493 int initialSize)
494{
495 if (list->items == NULL) {
496 if (initialSize <= 0)
497 initialSize = 1;
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800498 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000499 if (list->items == NULL) {
500 xmlXPathErrMemory(NULL,
501 "xmlPointerListCreate: allocating item\n");
502 return(-1);
503 }
504 list->number = 0;
505 list->size = initialSize;
506 } else if (list->size <= list->number) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800507 if (list->size > 50000000) {
508 xmlXPathErrMemory(NULL,
509 "xmlPointerListAddSize: re-allocating item\n");
510 return(-1);
511 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000512 list->size *= 2;
513 list->items = (void **) xmlRealloc(list->items,
514 list->size * sizeof(void *));
515 if (list->items == NULL) {
516 xmlXPathErrMemory(NULL,
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800517 "xmlPointerListAddSize: re-allocating item\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000518 list->size = 0;
519 return(-1);
520 }
521 }
522 list->items[list->number++] = item;
523 return(0);
524}
525
526/**
527 * xsltPointerListCreate:
528 *
529 * Creates an xsltPointerList structure.
530 *
531 * Returns a xsltPointerList structure or NULL in case of an error.
532 */
533static xmlPointerListPtr
534xmlPointerListCreate(int initialSize)
535{
536 xmlPointerListPtr ret;
537
538 ret = xmlMalloc(sizeof(xmlPointerList));
539 if (ret == NULL) {
540 xmlXPathErrMemory(NULL,
541 "xmlPointerListCreate: allocating item\n");
542 return (NULL);
543 }
544 memset(ret, 0, sizeof(xmlPointerList));
545 if (initialSize > 0) {
546 xmlPointerListAddSize(ret, NULL, initialSize);
547 ret->number = 0;
548 }
549 return (ret);
550}
551
552/**
553 * xsltPointerListFree:
554 *
555 * Frees the xsltPointerList structure. This does not free
556 * the content of the list.
557 */
558static void
559xmlPointerListFree(xmlPointerListPtr list)
560{
561 if (list == NULL)
562 return;
563 if (list->items != NULL)
564 xmlFree(list->items);
565 xmlFree(list);
566}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000567
568/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000569 * *
570 * Parser Types *
571 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000572 ************************************************************************/
573
574/*
575 * Types are private:
576 */
577
578typedef enum {
579 XPATH_OP_END=0,
580 XPATH_OP_AND,
581 XPATH_OP_OR,
582 XPATH_OP_EQUAL,
583 XPATH_OP_CMP,
584 XPATH_OP_PLUS,
585 XPATH_OP_MULT,
586 XPATH_OP_UNION,
587 XPATH_OP_ROOT,
588 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000589 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000590 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000591 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000592 XPATH_OP_VARIABLE,
593 XPATH_OP_FUNCTION,
594 XPATH_OP_ARG,
595 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000596 XPATH_OP_FILTER, /* 17 */
597 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000598#ifdef LIBXML_XPTR_ENABLED
599 ,XPATH_OP_RANGETO
600#endif
601} xmlXPathOp;
602
603typedef enum {
604 AXIS_ANCESTOR = 1,
605 AXIS_ANCESTOR_OR_SELF,
606 AXIS_ATTRIBUTE,
607 AXIS_CHILD,
608 AXIS_DESCENDANT,
609 AXIS_DESCENDANT_OR_SELF,
610 AXIS_FOLLOWING,
611 AXIS_FOLLOWING_SIBLING,
612 AXIS_NAMESPACE,
613 AXIS_PARENT,
614 AXIS_PRECEDING,
615 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000616 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000617} xmlXPathAxisVal;
618
619typedef enum {
620 NODE_TEST_NONE = 0,
621 NODE_TEST_TYPE = 1,
622 NODE_TEST_PI = 2,
623 NODE_TEST_ALL = 3,
624 NODE_TEST_NS = 4,
625 NODE_TEST_NAME = 5
626} xmlXPathTestVal;
627
628typedef enum {
629 NODE_TYPE_NODE = 0,
630 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
631 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000632 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000633} xmlXPathTypeVal;
634
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000635typedef struct _xmlXPathStepOp xmlXPathStepOp;
636typedef xmlXPathStepOp *xmlXPathStepOpPtr;
637struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000638 xmlXPathOp op; /* The identifier of the operation */
639 int ch1; /* First child */
640 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000641 int value;
642 int value2;
643 int value3;
644 void *value4;
645 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000646 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000647 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000648};
649
650struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000651 int nbStep; /* Number of steps in this expression */
652 int maxStep; /* Maximum number of steps allocated */
653 xmlXPathStepOp *steps; /* ops for computation of this expression */
654 int last; /* index of last step in expression */
655 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000656 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000657#ifdef DEBUG_EVAL_COUNTS
658 int nb;
659 xmlChar *string;
660#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000661#ifdef XPATH_STREAMING
662 xmlPatternPtr stream;
663#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000664};
665
666/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000667 * *
668 * Forward declarations *
669 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000670 ************************************************************************/
671static void
672xmlXPathFreeValueTree(xmlNodeSetPtr obj);
673static void
674xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
675static int
676xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
677 xmlXPathStepOpPtr op, xmlNodePtr *first);
678static int
679xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000680 xmlXPathStepOpPtr op,
681 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000682
683/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000684 * *
685 * Parser Type functions *
686 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000687 ************************************************************************/
688
689/**
690 * xmlXPathNewCompExpr:
691 *
692 * Create a new Xpath component
693 *
694 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
695 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000696static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000697xmlXPathNewCompExpr(void) {
698 xmlXPathCompExprPtr cur;
699
700 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
701 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000702 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000703 return(NULL);
704 }
705 memset(cur, 0, sizeof(xmlXPathCompExpr));
706 cur->maxStep = 10;
707 cur->nbStep = 0;
708 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
709 sizeof(xmlXPathStepOp));
710 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000711 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000712 xmlFree(cur);
713 return(NULL);
714 }
715 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
716 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000717#ifdef DEBUG_EVAL_COUNTS
718 cur->nb = 0;
719#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000720 return(cur);
721}
722
723/**
724 * xmlXPathFreeCompExpr:
725 * @comp: an XPATH comp
726 *
727 * Free up the memory allocated by @comp
728 */
729void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000730xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
731{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000732 xmlXPathStepOpPtr op;
733 int i;
734
735 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000736 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000737 if (comp->dict == NULL) {
738 for (i = 0; i < comp->nbStep; i++) {
739 op = &comp->steps[i];
740 if (op->value4 != NULL) {
741 if (op->op == XPATH_OP_VALUE)
742 xmlXPathFreeObject(op->value4);
743 else
744 xmlFree(op->value4);
745 }
746 if (op->value5 != NULL)
747 xmlFree(op->value5);
748 }
749 } else {
750 for (i = 0; i < comp->nbStep; i++) {
751 op = &comp->steps[i];
752 if (op->value4 != NULL) {
753 if (op->op == XPATH_OP_VALUE)
754 xmlXPathFreeObject(op->value4);
755 }
756 }
757 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000758 }
759 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000760 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000761 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000762#ifdef DEBUG_EVAL_COUNTS
763 if (comp->string != NULL) {
764 xmlFree(comp->string);
765 }
766#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000767#ifdef XPATH_STREAMING
768 if (comp->stream != NULL) {
769 xmlFreePatternList(comp->stream);
770 }
771#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000772 if (comp->expr != NULL) {
773 xmlFree(comp->expr);
774 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000775
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000776 xmlFree(comp);
777}
778
779/**
780 * xmlXPathCompExprAdd:
781 * @comp: the compiled expression
782 * @ch1: first child index
783 * @ch2: second child index
784 * @op: an op
785 * @value: the first int value
786 * @value2: the second int value
787 * @value3: the third int value
788 * @value4: the first string value
789 * @value5: the second string value
790 *
William M. Brack08171912003-12-29 02:52:11 +0000791 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000792 *
793 * Returns -1 in case of failure, the index otherwise
794 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000795static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000796xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
797 xmlXPathOp op, int value,
798 int value2, int value3, void *value4, void *value5) {
799 if (comp->nbStep >= comp->maxStep) {
800 xmlXPathStepOp *real;
801
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800802 if (comp->maxStep >= XPATH_MAX_STEPS) {
803 xmlXPathErrMemory(NULL, "adding step\n");
804 return(-1);
805 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000806 comp->maxStep *= 2;
807 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
808 comp->maxStep * sizeof(xmlXPathStepOp));
809 if (real == NULL) {
810 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000811 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000812 return(-1);
813 }
814 comp->steps = real;
815 }
816 comp->last = comp->nbStep;
817 comp->steps[comp->nbStep].ch1 = ch1;
818 comp->steps[comp->nbStep].ch2 = ch2;
819 comp->steps[comp->nbStep].op = op;
820 comp->steps[comp->nbStep].value = value;
821 comp->steps[comp->nbStep].value2 = value2;
822 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000823 if ((comp->dict != NULL) &&
824 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
825 (op == XPATH_OP_COLLECT))) {
826 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000827 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000828 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000829 xmlFree(value4);
830 } else
831 comp->steps[comp->nbStep].value4 = NULL;
832 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000833 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000834 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000835 xmlFree(value5);
836 } else
837 comp->steps[comp->nbStep].value5 = NULL;
838 } else {
839 comp->steps[comp->nbStep].value4 = value4;
840 comp->steps[comp->nbStep].value5 = value5;
841 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000842 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000843 return(comp->nbStep++);
844}
845
Daniel Veillardf06307e2001-07-03 10:35:50 +0000846/**
847 * xmlXPathCompSwap:
848 * @comp: the compiled expression
849 * @op: operation index
850 *
851 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000852 */
853static void
854xmlXPathCompSwap(xmlXPathStepOpPtr op) {
855 int tmp;
856
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000857#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000858 /*
859 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000860 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000861 * application
862 */
863 if (xmlXPathDisableOptimizer)
864 return;
865#endif
866
Daniel Veillardf06307e2001-07-03 10:35:50 +0000867 tmp = op->ch1;
868 op->ch1 = op->ch2;
869 op->ch2 = tmp;
870}
871
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000872#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
873 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
874 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000875#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
876 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
877 (op), (val), (val2), (val3), (val4), (val5))
878
Daniel Veillard45490ae2008-07-29 09:13:19 +0000879#define PUSH_LEAVE_EXPR(op, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000880xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
881
Daniel Veillard45490ae2008-07-29 09:13:19 +0000882#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000883xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
884
Daniel Veillard45490ae2008-07-29 09:13:19 +0000885#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000886xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
887 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000888
889/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000890 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000891 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000892 * *
893 ************************************************************************/
894
895/* #define XP_DEFAULT_CACHE_ON */
896
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000897#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000898
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000899typedef struct _xmlXPathContextCache xmlXPathContextCache;
900typedef xmlXPathContextCache *xmlXPathContextCachePtr;
901struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000902 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
903 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
904 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
905 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
906 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000907 int maxNodeset;
908 int maxString;
909 int maxBoolean;
910 int maxNumber;
911 int maxMisc;
912#ifdef XP_DEBUG_OBJ_USAGE
913 int dbgCachedAll;
914 int dbgCachedNodeset;
915 int dbgCachedString;
916 int dbgCachedBool;
917 int dbgCachedNumber;
918 int dbgCachedPoint;
919 int dbgCachedRange;
920 int dbgCachedLocset;
921 int dbgCachedUsers;
922 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000923 int dbgCachedUndefined;
924
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000925
926 int dbgReusedAll;
927 int dbgReusedNodeset;
928 int dbgReusedString;
929 int dbgReusedBool;
930 int dbgReusedNumber;
931 int dbgReusedPoint;
932 int dbgReusedRange;
933 int dbgReusedLocset;
934 int dbgReusedUsers;
935 int dbgReusedXSLTTree;
936 int dbgReusedUndefined;
937
938#endif
939};
940
941/************************************************************************
942 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000943 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +0000944 * *
945 ************************************************************************/
946
Daniel Veillard45490ae2008-07-29 09:13:19 +0000947#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +0000948 xmlGenericError(xmlGenericErrorContext, \
949 "Internal error at %s:%d\n", \
950 __FILE__, __LINE__);
951
952#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000953static void
954xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000955 int i;
956 char shift[100];
957
958 for (i = 0;((i < depth) && (i < 25));i++)
959 shift[2 * i] = shift[2 * i + 1] = ' ';
960 shift[2 * i] = shift[2 * i + 1] = 0;
961 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200962 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000963 fprintf(output, "Node is NULL !\n");
964 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000965
Owen Taylor3473f882001-02-23 17:55:21 +0000966 }
967
968 if ((cur->type == XML_DOCUMENT_NODE) ||
969 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200970 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000971 fprintf(output, " /\n");
972 } else if (cur->type == XML_ATTRIBUTE_NODE)
973 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
974 else
975 xmlDebugDumpOneNode(output, cur, depth);
976}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000977static void
978xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000979 xmlNodePtr tmp;
980 int i;
981 char shift[100];
982
983 for (i = 0;((i < depth) && (i < 25));i++)
984 shift[2 * i] = shift[2 * i + 1] = ' ';
985 shift[2 * i] = shift[2 * i + 1] = 0;
986 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200987 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000988 fprintf(output, "Node is NULL !\n");
989 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000990
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000991 }
992
993 while (cur != NULL) {
994 tmp = cur;
995 cur = cur->next;
996 xmlDebugDumpOneNode(output, tmp, depth);
997 }
998}
Owen Taylor3473f882001-02-23 17:55:21 +0000999
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001000static void
1001xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001002 int i;
1003 char shift[100];
1004
1005 for (i = 0;((i < depth) && (i < 25));i++)
1006 shift[2 * i] = shift[2 * i + 1] = ' ';
1007 shift[2 * i] = shift[2 * i + 1] = 0;
1008
1009 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001010 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001011 fprintf(output, "NodeSet is NULL !\n");
1012 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001013
Owen Taylor3473f882001-02-23 17:55:21 +00001014 }
1015
Daniel Veillard911f49a2001-04-07 15:39:35 +00001016 if (cur != NULL) {
1017 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1018 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001019 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +00001020 fprintf(output, "%d", i + 1);
1021 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1022 }
Owen Taylor3473f882001-02-23 17:55:21 +00001023 }
1024}
1025
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001026static void
1027xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001028 int i;
1029 char shift[100];
1030
1031 for (i = 0;((i < depth) && (i < 25));i++)
1032 shift[2 * i] = shift[2 * i + 1] = ' ';
1033 shift[2 * i] = shift[2 * i + 1] = 0;
1034
1035 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001036 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001037 fprintf(output, "Value Tree is NULL !\n");
1038 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001039
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001040 }
1041
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001042 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001043 fprintf(output, "%d", i + 1);
1044 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1045}
Owen Taylor3473f882001-02-23 17:55:21 +00001046#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001047static void
1048xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001049 int i;
1050 char shift[100];
1051
1052 for (i = 0;((i < depth) && (i < 25));i++)
1053 shift[2 * i] = shift[2 * i + 1] = ' ';
1054 shift[2 * i] = shift[2 * i + 1] = 0;
1055
1056 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001057 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001058 fprintf(output, "LocationSet is NULL !\n");
1059 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001060
Owen Taylor3473f882001-02-23 17:55:21 +00001061 }
1062
1063 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001064 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001065 fprintf(output, "%d : ", i + 1);
1066 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1067 }
1068}
Daniel Veillard017b1082001-06-21 11:20:21 +00001069#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001070
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00001071/**
1072 * xmlXPathDebugDumpObject:
1073 * @output: the FILE * to dump the output
1074 * @cur: the object to inspect
1075 * @depth: indentation level
1076 *
1077 * Dump the content of the object for debugging purposes
1078 */
1079void
1080xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001081 int i;
1082 char shift[100];
1083
Daniel Veillarda82b1822004-11-08 16:24:57 +00001084 if (output == NULL) return;
1085
Owen Taylor3473f882001-02-23 17:55:21 +00001086 for (i = 0;((i < depth) && (i < 25));i++)
1087 shift[2 * i] = shift[2 * i + 1] = ' ';
1088 shift[2 * i] = shift[2 * i + 1] = 0;
1089
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001090
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001091 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001092
1093 if (cur == NULL) {
1094 fprintf(output, "Object is empty (NULL)\n");
1095 return;
1096 }
1097 switch(cur->type) {
1098 case XPATH_UNDEFINED:
1099 fprintf(output, "Object is uninitialized\n");
1100 break;
1101 case XPATH_NODESET:
1102 fprintf(output, "Object is a Node Set :\n");
1103 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1104 break;
1105 case XPATH_XSLT_TREE:
1106 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001107 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001108 break;
1109 case XPATH_BOOLEAN:
1110 fprintf(output, "Object is a Boolean : ");
1111 if (cur->boolval) fprintf(output, "true\n");
1112 else fprintf(output, "false\n");
1113 break;
1114 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001115 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001116 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001117 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001118 break;
1119 case -1:
1120 fprintf(output, "Object is a number : -Infinity\n");
1121 break;
1122 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001123 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001124 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001125 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1126 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001127 } else {
1128 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1129 }
1130 }
Owen Taylor3473f882001-02-23 17:55:21 +00001131 break;
1132 case XPATH_STRING:
1133 fprintf(output, "Object is a string : ");
1134 xmlDebugDumpString(output, cur->stringval);
1135 fprintf(output, "\n");
1136 break;
1137 case XPATH_POINT:
1138 fprintf(output, "Object is a point : index %d in node", cur->index);
1139 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1140 fprintf(output, "\n");
1141 break;
1142 case XPATH_RANGE:
1143 if ((cur->user2 == NULL) ||
1144 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1145 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001146 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001147 if (cur->index >= 0)
1148 fprintf(output, "index %d in ", cur->index);
1149 fprintf(output, "node\n");
1150 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1151 depth + 1);
1152 } else {
1153 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001154 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001155 fprintf(output, "From ");
1156 if (cur->index >= 0)
1157 fprintf(output, "index %d in ", cur->index);
1158 fprintf(output, "node\n");
1159 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1160 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001161 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001162 fprintf(output, "To ");
1163 if (cur->index2 >= 0)
1164 fprintf(output, "index %d in ", cur->index2);
1165 fprintf(output, "node\n");
1166 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1167 depth + 1);
1168 fprintf(output, "\n");
1169 }
1170 break;
1171 case XPATH_LOCATIONSET:
1172#if defined(LIBXML_XPTR_ENABLED)
1173 fprintf(output, "Object is a Location Set:\n");
1174 xmlXPathDebugDumpLocationSet(output,
1175 (xmlLocationSetPtr) cur->user, depth);
1176#endif
1177 break;
1178 case XPATH_USERS:
1179 fprintf(output, "Object is user defined\n");
1180 break;
1181 }
1182}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001183
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001184static void
1185xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001186 xmlXPathStepOpPtr op, int depth) {
1187 int i;
1188 char shift[100];
1189
1190 for (i = 0;((i < depth) && (i < 25));i++)
1191 shift[2 * i] = shift[2 * i + 1] = ' ';
1192 shift[2 * i] = shift[2 * i + 1] = 0;
1193
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001194 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001195 if (op == NULL) {
1196 fprintf(output, "Step is NULL\n");
1197 return;
1198 }
1199 switch (op->op) {
1200 case XPATH_OP_END:
1201 fprintf(output, "END"); break;
1202 case XPATH_OP_AND:
1203 fprintf(output, "AND"); break;
1204 case XPATH_OP_OR:
1205 fprintf(output, "OR"); break;
1206 case XPATH_OP_EQUAL:
1207 if (op->value)
1208 fprintf(output, "EQUAL =");
1209 else
1210 fprintf(output, "EQUAL !=");
1211 break;
1212 case XPATH_OP_CMP:
1213 if (op->value)
1214 fprintf(output, "CMP <");
1215 else
1216 fprintf(output, "CMP >");
1217 if (!op->value2)
1218 fprintf(output, "=");
1219 break;
1220 case XPATH_OP_PLUS:
1221 if (op->value == 0)
1222 fprintf(output, "PLUS -");
1223 else if (op->value == 1)
1224 fprintf(output, "PLUS +");
1225 else if (op->value == 2)
1226 fprintf(output, "PLUS unary -");
1227 else if (op->value == 3)
1228 fprintf(output, "PLUS unary - -");
1229 break;
1230 case XPATH_OP_MULT:
1231 if (op->value == 0)
1232 fprintf(output, "MULT *");
1233 else if (op->value == 1)
1234 fprintf(output, "MULT div");
1235 else
1236 fprintf(output, "MULT mod");
1237 break;
1238 case XPATH_OP_UNION:
1239 fprintf(output, "UNION"); break;
1240 case XPATH_OP_ROOT:
1241 fprintf(output, "ROOT"); break;
1242 case XPATH_OP_NODE:
1243 fprintf(output, "NODE"); break;
1244 case XPATH_OP_RESET:
1245 fprintf(output, "RESET"); break;
1246 case XPATH_OP_SORT:
1247 fprintf(output, "SORT"); break;
1248 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001249 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1250 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1251 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001252 const xmlChar *prefix = op->value4;
1253 const xmlChar *name = op->value5;
1254
1255 fprintf(output, "COLLECT ");
1256 switch (axis) {
1257 case AXIS_ANCESTOR:
1258 fprintf(output, " 'ancestors' "); break;
1259 case AXIS_ANCESTOR_OR_SELF:
1260 fprintf(output, " 'ancestors-or-self' "); break;
1261 case AXIS_ATTRIBUTE:
1262 fprintf(output, " 'attributes' "); break;
1263 case AXIS_CHILD:
1264 fprintf(output, " 'child' "); break;
1265 case AXIS_DESCENDANT:
1266 fprintf(output, " 'descendant' "); break;
1267 case AXIS_DESCENDANT_OR_SELF:
1268 fprintf(output, " 'descendant-or-self' "); break;
1269 case AXIS_FOLLOWING:
1270 fprintf(output, " 'following' "); break;
1271 case AXIS_FOLLOWING_SIBLING:
1272 fprintf(output, " 'following-siblings' "); break;
1273 case AXIS_NAMESPACE:
1274 fprintf(output, " 'namespace' "); break;
1275 case AXIS_PARENT:
1276 fprintf(output, " 'parent' "); break;
1277 case AXIS_PRECEDING:
1278 fprintf(output, " 'preceding' "); break;
1279 case AXIS_PRECEDING_SIBLING:
1280 fprintf(output, " 'preceding-sibling' "); break;
1281 case AXIS_SELF:
1282 fprintf(output, " 'self' "); break;
1283 }
1284 switch (test) {
1285 case NODE_TEST_NONE:
1286 fprintf(output, "'none' "); break;
1287 case NODE_TEST_TYPE:
1288 fprintf(output, "'type' "); break;
1289 case NODE_TEST_PI:
1290 fprintf(output, "'PI' "); break;
1291 case NODE_TEST_ALL:
1292 fprintf(output, "'all' "); break;
1293 case NODE_TEST_NS:
1294 fprintf(output, "'namespace' "); break;
1295 case NODE_TEST_NAME:
1296 fprintf(output, "'name' "); break;
1297 }
1298 switch (type) {
1299 case NODE_TYPE_NODE:
1300 fprintf(output, "'node' "); break;
1301 case NODE_TYPE_COMMENT:
1302 fprintf(output, "'comment' "); break;
1303 case NODE_TYPE_TEXT:
1304 fprintf(output, "'text' "); break;
1305 case NODE_TYPE_PI:
1306 fprintf(output, "'PI' "); break;
1307 }
1308 if (prefix != NULL)
1309 fprintf(output, "%s:", prefix);
1310 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001311 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001312 break;
1313
1314 }
1315 case XPATH_OP_VALUE: {
1316 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1317
1318 fprintf(output, "ELEM ");
1319 xmlXPathDebugDumpObject(output, object, 0);
1320 goto finish;
1321 }
1322 case XPATH_OP_VARIABLE: {
1323 const xmlChar *prefix = op->value5;
1324 const xmlChar *name = op->value4;
1325
1326 if (prefix != NULL)
1327 fprintf(output, "VARIABLE %s:%s", prefix, name);
1328 else
1329 fprintf(output, "VARIABLE %s", name);
1330 break;
1331 }
1332 case XPATH_OP_FUNCTION: {
1333 int nbargs = op->value;
1334 const xmlChar *prefix = op->value5;
1335 const xmlChar *name = op->value4;
1336
1337 if (prefix != NULL)
1338 fprintf(output, "FUNCTION %s:%s(%d args)",
1339 prefix, name, nbargs);
1340 else
1341 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1342 break;
1343 }
1344 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1345 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001346 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001347#ifdef LIBXML_XPTR_ENABLED
1348 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1349#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001350 default:
1351 fprintf(output, "UNKNOWN %d\n", op->op); return;
1352 }
1353 fprintf(output, "\n");
1354finish:
1355 if (op->ch1 >= 0)
1356 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1357 if (op->ch2 >= 0)
1358 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1359}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001360
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001361/**
1362 * xmlXPathDebugDumpCompExpr:
1363 * @output: the FILE * for the output
1364 * @comp: the precompiled XPath expression
1365 * @depth: the indentation level.
1366 *
1367 * Dumps the tree of the compiled XPath expression.
1368 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001369void
1370xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1371 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001372 int i;
1373 char shift[100];
1374
Daniel Veillarda82b1822004-11-08 16:24:57 +00001375 if ((output == NULL) || (comp == NULL)) return;
1376
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001377 for (i = 0;((i < depth) && (i < 25));i++)
1378 shift[2 * i] = shift[2 * i + 1] = ' ';
1379 shift[2 * i] = shift[2 * i + 1] = 0;
1380
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001381 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001382
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001383 fprintf(output, "Compiled Expression : %d elements\n",
1384 comp->nbStep);
1385 i = comp->last;
1386 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1387}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001388
1389#ifdef XP_DEBUG_OBJ_USAGE
1390
1391/*
1392* XPath object usage related debugging variables.
1393*/
1394static int xmlXPathDebugObjCounterUndefined = 0;
1395static int xmlXPathDebugObjCounterNodeset = 0;
1396static int xmlXPathDebugObjCounterBool = 0;
1397static int xmlXPathDebugObjCounterNumber = 0;
1398static int xmlXPathDebugObjCounterString = 0;
1399static int xmlXPathDebugObjCounterPoint = 0;
1400static int xmlXPathDebugObjCounterRange = 0;
1401static int xmlXPathDebugObjCounterLocset = 0;
1402static int xmlXPathDebugObjCounterUsers = 0;
1403static int xmlXPathDebugObjCounterXSLTTree = 0;
1404static int xmlXPathDebugObjCounterAll = 0;
1405
1406static int xmlXPathDebugObjTotalUndefined = 0;
1407static int xmlXPathDebugObjTotalNodeset = 0;
1408static int xmlXPathDebugObjTotalBool = 0;
1409static int xmlXPathDebugObjTotalNumber = 0;
1410static int xmlXPathDebugObjTotalString = 0;
1411static int xmlXPathDebugObjTotalPoint = 0;
1412static int xmlXPathDebugObjTotalRange = 0;
1413static int xmlXPathDebugObjTotalLocset = 0;
1414static int xmlXPathDebugObjTotalUsers = 0;
1415static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001416static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001417
1418static int xmlXPathDebugObjMaxUndefined = 0;
1419static int xmlXPathDebugObjMaxNodeset = 0;
1420static int xmlXPathDebugObjMaxBool = 0;
1421static int xmlXPathDebugObjMaxNumber = 0;
1422static int xmlXPathDebugObjMaxString = 0;
1423static int xmlXPathDebugObjMaxPoint = 0;
1424static int xmlXPathDebugObjMaxRange = 0;
1425static int xmlXPathDebugObjMaxLocset = 0;
1426static int xmlXPathDebugObjMaxUsers = 0;
1427static int xmlXPathDebugObjMaxXSLTTree = 0;
1428static int xmlXPathDebugObjMaxAll = 0;
1429
1430/* REVISIT TODO: Make this static when committing */
1431static void
1432xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1433{
1434 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001435 if (ctxt->cache != NULL) {
1436 xmlXPathContextCachePtr cache =
1437 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001438
1439 cache->dbgCachedAll = 0;
1440 cache->dbgCachedNodeset = 0;
1441 cache->dbgCachedString = 0;
1442 cache->dbgCachedBool = 0;
1443 cache->dbgCachedNumber = 0;
1444 cache->dbgCachedPoint = 0;
1445 cache->dbgCachedRange = 0;
1446 cache->dbgCachedLocset = 0;
1447 cache->dbgCachedUsers = 0;
1448 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001449 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001450
1451 cache->dbgReusedAll = 0;
1452 cache->dbgReusedNodeset = 0;
1453 cache->dbgReusedString = 0;
1454 cache->dbgReusedBool = 0;
1455 cache->dbgReusedNumber = 0;
1456 cache->dbgReusedPoint = 0;
1457 cache->dbgReusedRange = 0;
1458 cache->dbgReusedLocset = 0;
1459 cache->dbgReusedUsers = 0;
1460 cache->dbgReusedXSLTTree = 0;
1461 cache->dbgReusedUndefined = 0;
1462 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001463 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001464
1465 xmlXPathDebugObjCounterUndefined = 0;
1466 xmlXPathDebugObjCounterNodeset = 0;
1467 xmlXPathDebugObjCounterBool = 0;
1468 xmlXPathDebugObjCounterNumber = 0;
1469 xmlXPathDebugObjCounterString = 0;
1470 xmlXPathDebugObjCounterPoint = 0;
1471 xmlXPathDebugObjCounterRange = 0;
1472 xmlXPathDebugObjCounterLocset = 0;
1473 xmlXPathDebugObjCounterUsers = 0;
1474 xmlXPathDebugObjCounterXSLTTree = 0;
1475 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001476
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001477 xmlXPathDebugObjTotalUndefined = 0;
1478 xmlXPathDebugObjTotalNodeset = 0;
1479 xmlXPathDebugObjTotalBool = 0;
1480 xmlXPathDebugObjTotalNumber = 0;
1481 xmlXPathDebugObjTotalString = 0;
1482 xmlXPathDebugObjTotalPoint = 0;
1483 xmlXPathDebugObjTotalRange = 0;
1484 xmlXPathDebugObjTotalLocset = 0;
1485 xmlXPathDebugObjTotalUsers = 0;
1486 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001487 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001488
1489 xmlXPathDebugObjMaxUndefined = 0;
1490 xmlXPathDebugObjMaxNodeset = 0;
1491 xmlXPathDebugObjMaxBool = 0;
1492 xmlXPathDebugObjMaxNumber = 0;
1493 xmlXPathDebugObjMaxString = 0;
1494 xmlXPathDebugObjMaxPoint = 0;
1495 xmlXPathDebugObjMaxRange = 0;
1496 xmlXPathDebugObjMaxLocset = 0;
1497 xmlXPathDebugObjMaxUsers = 0;
1498 xmlXPathDebugObjMaxXSLTTree = 0;
1499 xmlXPathDebugObjMaxAll = 0;
1500
1501}
1502
1503static void
1504xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1505 xmlXPathObjectType objType)
1506{
1507 int isCached = 0;
1508
1509 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001510 if (ctxt->cache != NULL) {
1511 xmlXPathContextCachePtr cache =
1512 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001513
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001514 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001515
1516 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001517 switch (objType) {
1518 case XPATH_UNDEFINED:
1519 cache->dbgReusedUndefined++;
1520 break;
1521 case XPATH_NODESET:
1522 cache->dbgReusedNodeset++;
1523 break;
1524 case XPATH_BOOLEAN:
1525 cache->dbgReusedBool++;
1526 break;
1527 case XPATH_NUMBER:
1528 cache->dbgReusedNumber++;
1529 break;
1530 case XPATH_STRING:
1531 cache->dbgReusedString++;
1532 break;
1533 case XPATH_POINT:
1534 cache->dbgReusedPoint++;
1535 break;
1536 case XPATH_RANGE:
1537 cache->dbgReusedRange++;
1538 break;
1539 case XPATH_LOCATIONSET:
1540 cache->dbgReusedLocset++;
1541 break;
1542 case XPATH_USERS:
1543 cache->dbgReusedUsers++;
1544 break;
1545 case XPATH_XSLT_TREE:
1546 cache->dbgReusedXSLTTree++;
1547 break;
1548 default:
1549 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001550 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001551 }
1552 }
1553
1554 switch (objType) {
1555 case XPATH_UNDEFINED:
1556 if (! isCached)
1557 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001558 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001559 if (xmlXPathDebugObjCounterUndefined >
1560 xmlXPathDebugObjMaxUndefined)
1561 xmlXPathDebugObjMaxUndefined =
1562 xmlXPathDebugObjCounterUndefined;
1563 break;
1564 case XPATH_NODESET:
1565 if (! isCached)
1566 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001567 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001568 if (xmlXPathDebugObjCounterNodeset >
1569 xmlXPathDebugObjMaxNodeset)
1570 xmlXPathDebugObjMaxNodeset =
1571 xmlXPathDebugObjCounterNodeset;
1572 break;
1573 case XPATH_BOOLEAN:
1574 if (! isCached)
1575 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001576 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001577 if (xmlXPathDebugObjCounterBool >
1578 xmlXPathDebugObjMaxBool)
1579 xmlXPathDebugObjMaxBool =
1580 xmlXPathDebugObjCounterBool;
1581 break;
1582 case XPATH_NUMBER:
1583 if (! isCached)
1584 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001585 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001586 if (xmlXPathDebugObjCounterNumber >
1587 xmlXPathDebugObjMaxNumber)
1588 xmlXPathDebugObjMaxNumber =
1589 xmlXPathDebugObjCounterNumber;
1590 break;
1591 case XPATH_STRING:
1592 if (! isCached)
1593 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001594 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001595 if (xmlXPathDebugObjCounterString >
1596 xmlXPathDebugObjMaxString)
1597 xmlXPathDebugObjMaxString =
1598 xmlXPathDebugObjCounterString;
1599 break;
1600 case XPATH_POINT:
1601 if (! isCached)
1602 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001603 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001604 if (xmlXPathDebugObjCounterPoint >
1605 xmlXPathDebugObjMaxPoint)
1606 xmlXPathDebugObjMaxPoint =
1607 xmlXPathDebugObjCounterPoint;
1608 break;
1609 case XPATH_RANGE:
1610 if (! isCached)
1611 xmlXPathDebugObjTotalRange++;
1612 xmlXPathDebugObjCounterRange++;
1613 if (xmlXPathDebugObjCounterRange >
1614 xmlXPathDebugObjMaxRange)
1615 xmlXPathDebugObjMaxRange =
1616 xmlXPathDebugObjCounterRange;
1617 break;
1618 case XPATH_LOCATIONSET:
1619 if (! isCached)
1620 xmlXPathDebugObjTotalLocset++;
1621 xmlXPathDebugObjCounterLocset++;
1622 if (xmlXPathDebugObjCounterLocset >
1623 xmlXPathDebugObjMaxLocset)
1624 xmlXPathDebugObjMaxLocset =
1625 xmlXPathDebugObjCounterLocset;
1626 break;
1627 case XPATH_USERS:
1628 if (! isCached)
1629 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001630 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001631 if (xmlXPathDebugObjCounterUsers >
1632 xmlXPathDebugObjMaxUsers)
1633 xmlXPathDebugObjMaxUsers =
1634 xmlXPathDebugObjCounterUsers;
1635 break;
1636 case XPATH_XSLT_TREE:
1637 if (! isCached)
1638 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001639 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001640 if (xmlXPathDebugObjCounterXSLTTree >
1641 xmlXPathDebugObjMaxXSLTTree)
1642 xmlXPathDebugObjMaxXSLTTree =
1643 xmlXPathDebugObjCounterXSLTTree;
1644 break;
1645 default:
1646 break;
1647 }
1648 if (! isCached)
1649 xmlXPathDebugObjTotalAll++;
1650 xmlXPathDebugObjCounterAll++;
1651 if (xmlXPathDebugObjCounterAll >
1652 xmlXPathDebugObjMaxAll)
1653 xmlXPathDebugObjMaxAll =
1654 xmlXPathDebugObjCounterAll;
1655}
1656
1657static void
1658xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1659 xmlXPathObjectType objType)
1660{
1661 int isCached = 0;
1662
1663 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001664 if (ctxt->cache != NULL) {
1665 xmlXPathContextCachePtr cache =
1666 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001667
Daniel Veillard45490ae2008-07-29 09:13:19 +00001668 isCached = 1;
1669
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001670 cache->dbgCachedAll++;
1671 switch (objType) {
1672 case XPATH_UNDEFINED:
1673 cache->dbgCachedUndefined++;
1674 break;
1675 case XPATH_NODESET:
1676 cache->dbgCachedNodeset++;
1677 break;
1678 case XPATH_BOOLEAN:
1679 cache->dbgCachedBool++;
1680 break;
1681 case XPATH_NUMBER:
1682 cache->dbgCachedNumber++;
1683 break;
1684 case XPATH_STRING:
1685 cache->dbgCachedString++;
1686 break;
1687 case XPATH_POINT:
1688 cache->dbgCachedPoint++;
1689 break;
1690 case XPATH_RANGE:
1691 cache->dbgCachedRange++;
1692 break;
1693 case XPATH_LOCATIONSET:
1694 cache->dbgCachedLocset++;
1695 break;
1696 case XPATH_USERS:
1697 cache->dbgCachedUsers++;
1698 break;
1699 case XPATH_XSLT_TREE:
1700 cache->dbgCachedXSLTTree++;
1701 break;
1702 default:
1703 break;
1704 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001705
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001706 }
1707 }
1708 switch (objType) {
1709 case XPATH_UNDEFINED:
1710 xmlXPathDebugObjCounterUndefined--;
1711 break;
1712 case XPATH_NODESET:
1713 xmlXPathDebugObjCounterNodeset--;
1714 break;
1715 case XPATH_BOOLEAN:
1716 xmlXPathDebugObjCounterBool--;
1717 break;
1718 case XPATH_NUMBER:
1719 xmlXPathDebugObjCounterNumber--;
1720 break;
1721 case XPATH_STRING:
1722 xmlXPathDebugObjCounterString--;
1723 break;
1724 case XPATH_POINT:
1725 xmlXPathDebugObjCounterPoint--;
1726 break;
1727 case XPATH_RANGE:
1728 xmlXPathDebugObjCounterRange--;
1729 break;
1730 case XPATH_LOCATIONSET:
1731 xmlXPathDebugObjCounterLocset--;
1732 break;
1733 case XPATH_USERS:
1734 xmlXPathDebugObjCounterUsers--;
1735 break;
1736 case XPATH_XSLT_TREE:
1737 xmlXPathDebugObjCounterXSLTTree--;
1738 break;
1739 default:
1740 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001741 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001742 xmlXPathDebugObjCounterAll--;
1743}
1744
1745/* REVISIT TODO: Make this static when committing */
1746static void
1747xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1748{
1749 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1750 reqXSLTTree, reqUndefined;
1751 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1752 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1753 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1754 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1755 int leftObjs = xmlXPathDebugObjCounterAll;
1756
1757 reqAll = xmlXPathDebugObjTotalAll;
1758 reqNodeset = xmlXPathDebugObjTotalNodeset;
1759 reqString = xmlXPathDebugObjTotalString;
1760 reqBool = xmlXPathDebugObjTotalBool;
1761 reqNumber = xmlXPathDebugObjTotalNumber;
1762 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1763 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001764
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001765 printf("# XPath object usage:\n");
1766
1767 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001768 if (ctxt->cache != NULL) {
1769 xmlXPathContextCachePtr cache =
1770 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001771
1772 reAll = cache->dbgReusedAll;
1773 reqAll += reAll;
1774 reNodeset = cache->dbgReusedNodeset;
1775 reqNodeset += reNodeset;
1776 reString = cache->dbgReusedString;
1777 reqString += reString;
1778 reBool = cache->dbgReusedBool;
1779 reqBool += reBool;
1780 reNumber = cache->dbgReusedNumber;
1781 reqNumber += reNumber;
1782 reXSLTTree = cache->dbgReusedXSLTTree;
1783 reqXSLTTree += reXSLTTree;
1784 reUndefined = cache->dbgReusedUndefined;
1785 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001786
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001787 caAll = cache->dbgCachedAll;
1788 caBool = cache->dbgCachedBool;
1789 caNodeset = cache->dbgCachedNodeset;
1790 caString = cache->dbgCachedString;
1791 caNumber = cache->dbgCachedNumber;
1792 caXSLTTree = cache->dbgCachedXSLTTree;
1793 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001794
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001795 if (cache->nodesetObjs)
1796 leftObjs -= cache->nodesetObjs->number;
1797 if (cache->stringObjs)
1798 leftObjs -= cache->stringObjs->number;
1799 if (cache->booleanObjs)
1800 leftObjs -= cache->booleanObjs->number;
1801 if (cache->numberObjs)
1802 leftObjs -= cache->numberObjs->number;
1803 if (cache->miscObjs)
1804 leftObjs -= cache->miscObjs->number;
1805 }
1806 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001807
1808 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001809 printf("# total : %d\n", reqAll);
1810 printf("# left : %d\n", leftObjs);
1811 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1812 printf("# reused : %d\n", reAll);
1813 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1814
1815 printf("# node-sets\n");
1816 printf("# total : %d\n", reqNodeset);
1817 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1818 printf("# reused : %d\n", reNodeset);
1819 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1820
1821 printf("# strings\n");
1822 printf("# total : %d\n", reqString);
1823 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1824 printf("# reused : %d\n", reString);
1825 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1826
1827 printf("# booleans\n");
1828 printf("# total : %d\n", reqBool);
1829 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1830 printf("# reused : %d\n", reBool);
1831 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1832
1833 printf("# numbers\n");
1834 printf("# total : %d\n", reqNumber);
1835 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1836 printf("# reused : %d\n", reNumber);
1837 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1838
1839 printf("# XSLT result tree fragments\n");
1840 printf("# total : %d\n", reqXSLTTree);
1841 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1842 printf("# reused : %d\n", reXSLTTree);
1843 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1844
1845 printf("# undefined\n");
1846 printf("# total : %d\n", reqUndefined);
1847 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1848 printf("# reused : %d\n", reUndefined);
1849 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1850
1851}
1852
1853#endif /* XP_DEBUG_OBJ_USAGE */
1854
Daniel Veillard017b1082001-06-21 11:20:21 +00001855#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001856
1857/************************************************************************
1858 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001859 * XPath object caching *
1860 * *
1861 ************************************************************************/
1862
1863/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001864 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001865 *
1866 * Create a new object cache
1867 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001868 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001869 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001870static xmlXPathContextCachePtr
1871xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001872{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001873 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001874
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001875 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001876 if (ret == NULL) {
1877 xmlXPathErrMemory(NULL, "creating object cache\n");
1878 return(NULL);
1879 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001880 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001881 ret->maxNodeset = 100;
1882 ret->maxString = 100;
1883 ret->maxBoolean = 100;
1884 ret->maxNumber = 100;
1885 ret->maxMisc = 100;
1886 return(ret);
1887}
1888
1889static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001890xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001891{
1892 int i;
1893 xmlXPathObjectPtr obj;
1894
1895 if (list == NULL)
1896 return;
1897
1898 for (i = 0; i < list->number; i++) {
1899 obj = list->items[i];
1900 /*
1901 * Note that it is already assured that we don't need to
1902 * look out for namespace nodes in the node-set.
1903 */
1904 if (obj->nodesetval != NULL) {
1905 if (obj->nodesetval->nodeTab != NULL)
1906 xmlFree(obj->nodesetval->nodeTab);
1907 xmlFree(obj->nodesetval);
1908 }
1909 xmlFree(obj);
1910#ifdef XP_DEBUG_OBJ_USAGE
1911 xmlXPathDebugObjCounterAll--;
1912#endif
1913 }
1914 xmlPointerListFree(list);
1915}
1916
1917static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001918xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001919{
1920 if (cache == NULL)
1921 return;
1922 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001923 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001924 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001925 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001926 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001927 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001928 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001929 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001930 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001931 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001932 xmlFree(cache);
1933}
1934
1935/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001936 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001937 *
1938 * @ctxt: the XPath context
1939 * @active: enables/disables (creates/frees) the cache
Daniel Veillard45490ae2008-07-29 09:13:19 +00001940 * @value: a value with semantics dependant on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001941 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001942 *
1943 * Creates/frees an object cache on the XPath context.
1944 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001945 * to be reused.
1946 * @options:
1947 * 0: This will set the XPath object caching:
1948 * @value:
1949 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001950 * to be cached per slot
1951 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001952 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001953 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001954 *
1955 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1956 */
1957int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001958xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1959 int active,
1960 int value,
1961 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001962{
1963 if (ctxt == NULL)
1964 return(-1);
1965 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001966 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001967
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001968 if (ctxt->cache == NULL) {
1969 ctxt->cache = xmlXPathNewCache();
1970 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001971 return(-1);
1972 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001973 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001974 if (options == 0) {
1975 if (value < 0)
1976 value = 100;
1977 cache->maxNodeset = value;
1978 cache->maxString = value;
1979 cache->maxNumber = value;
1980 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001981 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001982 }
1983 } else if (ctxt->cache != NULL) {
1984 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1985 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001986 }
1987 return(0);
1988}
1989
1990/**
1991 * xmlXPathCacheWrapNodeSet:
1992 * @ctxt: the XPath context
1993 * @val: the NodePtr value
1994 *
1995 * This is the cached version of xmlXPathWrapNodeSet().
1996 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1997 *
1998 * Returns the created or reused object.
1999 */
2000static xmlXPathObjectPtr
2001xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002002{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002003 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2004 xmlXPathContextCachePtr cache =
2005 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002006
2007 if ((cache->miscObjs != NULL) &&
2008 (cache->miscObjs->number != 0))
2009 {
2010 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002011
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002012 ret = (xmlXPathObjectPtr)
2013 cache->miscObjs->items[--cache->miscObjs->number];
2014 ret->type = XPATH_NODESET;
2015 ret->nodesetval = val;
2016#ifdef XP_DEBUG_OBJ_USAGE
2017 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2018#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00002019 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002020 }
2021 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002022
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002023 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00002024
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002025}
2026
2027/**
2028 * xmlXPathCacheWrapString:
2029 * @ctxt: the XPath context
2030 * @val: the xmlChar * value
2031 *
2032 * This is the cached version of xmlXPathWrapString().
2033 * Wraps the @val string into an XPath object.
2034 *
2035 * Returns the created or reused object.
2036 */
2037static xmlXPathObjectPtr
2038xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002039{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002040 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2041 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002042
2043 if ((cache->stringObjs != NULL) &&
2044 (cache->stringObjs->number != 0))
2045 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002046
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002047 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002048
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002049 ret = (xmlXPathObjectPtr)
2050 cache->stringObjs->items[--cache->stringObjs->number];
2051 ret->type = XPATH_STRING;
2052 ret->stringval = val;
2053#ifdef XP_DEBUG_OBJ_USAGE
2054 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2055#endif
2056 return(ret);
2057 } else if ((cache->miscObjs != NULL) &&
2058 (cache->miscObjs->number != 0))
2059 {
2060 xmlXPathObjectPtr ret;
2061 /*
2062 * Fallback to misc-cache.
2063 */
2064 ret = (xmlXPathObjectPtr)
2065 cache->miscObjs->items[--cache->miscObjs->number];
2066
2067 ret->type = XPATH_STRING;
2068 ret->stringval = val;
2069#ifdef XP_DEBUG_OBJ_USAGE
2070 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2071#endif
2072 return(ret);
2073 }
2074 }
2075 return(xmlXPathWrapString(val));
2076}
2077
2078/**
2079 * xmlXPathCacheNewNodeSet:
2080 * @ctxt: the XPath context
2081 * @val: the NodePtr value
2082 *
2083 * This is the cached version of xmlXPathNewNodeSet().
2084 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2085 * it with the single Node @val
2086 *
2087 * Returns the created or reused object.
2088 */
2089static xmlXPathObjectPtr
2090xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2091{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002092 if ((ctxt != NULL) && (ctxt->cache)) {
2093 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002094
2095 if ((cache->nodesetObjs != NULL) &&
2096 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002097 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002098 xmlXPathObjectPtr ret;
2099 /*
2100 * Use the nodset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002101 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002102 ret = (xmlXPathObjectPtr)
2103 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2104 ret->type = XPATH_NODESET;
2105 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002106 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002107 if ((ret->nodesetval->nodeMax == 0) ||
2108 (val->type == XML_NAMESPACE_DECL))
2109 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002110 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002111 } else {
2112 ret->nodesetval->nodeTab[0] = val;
2113 ret->nodesetval->nodeNr = 1;
2114 }
2115 }
2116#ifdef XP_DEBUG_OBJ_USAGE
2117 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2118#endif
2119 return(ret);
2120 } else if ((cache->miscObjs != NULL) &&
2121 (cache->miscObjs->number != 0))
2122 {
2123 xmlXPathObjectPtr ret;
2124 /*
2125 * Fallback to misc-cache.
2126 */
2127
2128 ret = (xmlXPathObjectPtr)
2129 cache->miscObjs->items[--cache->miscObjs->number];
2130
2131 ret->type = XPATH_NODESET;
2132 ret->boolval = 0;
2133 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08002134 if (ret->nodesetval == NULL) {
2135 ctxt->lastError.domain = XML_FROM_XPATH;
2136 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2137 return(NULL);
2138 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002139#ifdef XP_DEBUG_OBJ_USAGE
2140 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2141#endif
2142 return(ret);
2143 }
2144 }
2145 return(xmlXPathNewNodeSet(val));
2146}
2147
2148/**
2149 * xmlXPathCacheNewCString:
2150 * @ctxt: the XPath context
2151 * @val: the char * value
2152 *
2153 * This is the cached version of xmlXPathNewCString().
2154 * Acquire an xmlXPathObjectPtr of type string and of value @val
2155 *
2156 * Returns the created or reused object.
2157 */
2158static xmlXPathObjectPtr
2159xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002160{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002161 if ((ctxt != NULL) && (ctxt->cache)) {
2162 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002163
2164 if ((cache->stringObjs != NULL) &&
2165 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002166 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002167 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002168
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002169 ret = (xmlXPathObjectPtr)
2170 cache->stringObjs->items[--cache->stringObjs->number];
2171
2172 ret->type = XPATH_STRING;
2173 ret->stringval = xmlStrdup(BAD_CAST val);
2174#ifdef XP_DEBUG_OBJ_USAGE
2175 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2176#endif
2177 return(ret);
2178 } else if ((cache->miscObjs != NULL) &&
2179 (cache->miscObjs->number != 0))
2180 {
2181 xmlXPathObjectPtr ret;
2182
2183 ret = (xmlXPathObjectPtr)
2184 cache->miscObjs->items[--cache->miscObjs->number];
2185
2186 ret->type = XPATH_STRING;
2187 ret->stringval = xmlStrdup(BAD_CAST val);
2188#ifdef XP_DEBUG_OBJ_USAGE
2189 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2190#endif
2191 return(ret);
2192 }
2193 }
2194 return(xmlXPathNewCString(val));
2195}
2196
2197/**
2198 * xmlXPathCacheNewString:
2199 * @ctxt: the XPath context
2200 * @val: the xmlChar * value
2201 *
2202 * This is the cached version of xmlXPathNewString().
2203 * Acquire an xmlXPathObjectPtr of type string and of value @val
2204 *
2205 * Returns the created or reused object.
2206 */
2207static xmlXPathObjectPtr
2208xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002209{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002210 if ((ctxt != NULL) && (ctxt->cache)) {
2211 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002212
2213 if ((cache->stringObjs != NULL) &&
2214 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002215 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002216 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002217
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002218 ret = (xmlXPathObjectPtr)
2219 cache->stringObjs->items[--cache->stringObjs->number];
2220 ret->type = XPATH_STRING;
2221 if (val != NULL)
2222 ret->stringval = xmlStrdup(val);
2223 else
2224 ret->stringval = xmlStrdup((const xmlChar *)"");
2225#ifdef XP_DEBUG_OBJ_USAGE
2226 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2227#endif
2228 return(ret);
2229 } else if ((cache->miscObjs != NULL) &&
2230 (cache->miscObjs->number != 0))
2231 {
2232 xmlXPathObjectPtr ret;
2233
2234 ret = (xmlXPathObjectPtr)
2235 cache->miscObjs->items[--cache->miscObjs->number];
2236
2237 ret->type = XPATH_STRING;
2238 if (val != NULL)
2239 ret->stringval = xmlStrdup(val);
2240 else
2241 ret->stringval = xmlStrdup((const xmlChar *)"");
2242#ifdef XP_DEBUG_OBJ_USAGE
2243 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2244#endif
2245 return(ret);
2246 }
2247 }
2248 return(xmlXPathNewString(val));
2249}
2250
2251/**
2252 * xmlXPathCacheNewBoolean:
2253 * @ctxt: the XPath context
2254 * @val: the boolean value
2255 *
2256 * This is the cached version of xmlXPathNewBoolean().
2257 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2258 *
2259 * Returns the created or reused object.
2260 */
2261static xmlXPathObjectPtr
2262xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002263{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002264 if ((ctxt != NULL) && (ctxt->cache)) {
2265 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002266
2267 if ((cache->booleanObjs != NULL) &&
2268 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002269 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002270 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002271
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002272 ret = (xmlXPathObjectPtr)
2273 cache->booleanObjs->items[--cache->booleanObjs->number];
2274 ret->type = XPATH_BOOLEAN;
2275 ret->boolval = (val != 0);
2276#ifdef XP_DEBUG_OBJ_USAGE
2277 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2278#endif
2279 return(ret);
2280 } else if ((cache->miscObjs != NULL) &&
2281 (cache->miscObjs->number != 0))
2282 {
2283 xmlXPathObjectPtr ret;
2284
2285 ret = (xmlXPathObjectPtr)
2286 cache->miscObjs->items[--cache->miscObjs->number];
2287
2288 ret->type = XPATH_BOOLEAN;
2289 ret->boolval = (val != 0);
2290#ifdef XP_DEBUG_OBJ_USAGE
2291 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2292#endif
2293 return(ret);
2294 }
2295 }
2296 return(xmlXPathNewBoolean(val));
2297}
2298
2299/**
2300 * xmlXPathCacheNewFloat:
2301 * @ctxt: the XPath context
2302 * @val: the double value
2303 *
2304 * This is the cached version of xmlXPathNewFloat().
2305 * Acquires an xmlXPathObjectPtr of type double and of value @val
2306 *
2307 * Returns the created or reused object.
2308 */
2309static xmlXPathObjectPtr
2310xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2311{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002312 if ((ctxt != NULL) && (ctxt->cache)) {
2313 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002314
2315 if ((cache->numberObjs != NULL) &&
2316 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002317 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002318 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002319
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002320 ret = (xmlXPathObjectPtr)
2321 cache->numberObjs->items[--cache->numberObjs->number];
2322 ret->type = XPATH_NUMBER;
2323 ret->floatval = val;
2324#ifdef XP_DEBUG_OBJ_USAGE
2325 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2326#endif
2327 return(ret);
2328 } else if ((cache->miscObjs != NULL) &&
2329 (cache->miscObjs->number != 0))
2330 {
2331 xmlXPathObjectPtr ret;
2332
2333 ret = (xmlXPathObjectPtr)
2334 cache->miscObjs->items[--cache->miscObjs->number];
2335
2336 ret->type = XPATH_NUMBER;
2337 ret->floatval = val;
2338#ifdef XP_DEBUG_OBJ_USAGE
2339 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2340#endif
2341 return(ret);
2342 }
2343 }
2344 return(xmlXPathNewFloat(val));
2345}
2346
2347/**
2348 * xmlXPathCacheConvertString:
2349 * @ctxt: the XPath context
2350 * @val: an XPath object
2351 *
2352 * This is the cached version of xmlXPathConvertString().
2353 * Converts an existing object to its string() equivalent
2354 *
2355 * Returns a created or reused object, the old one is freed (cached)
2356 * (or the operation is done directly on @val)
2357 */
2358
2359static xmlXPathObjectPtr
2360xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002361 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002362
2363 if (val == NULL)
2364 return(xmlXPathCacheNewCString(ctxt, ""));
2365
2366 switch (val->type) {
2367 case XPATH_UNDEFINED:
2368#ifdef DEBUG_EXPR
2369 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2370#endif
2371 break;
2372 case XPATH_NODESET:
2373 case XPATH_XSLT_TREE:
2374 res = xmlXPathCastNodeSetToString(val->nodesetval);
2375 break;
2376 case XPATH_STRING:
2377 return(val);
2378 case XPATH_BOOLEAN:
2379 res = xmlXPathCastBooleanToString(val->boolval);
2380 break;
2381 case XPATH_NUMBER:
2382 res = xmlXPathCastNumberToString(val->floatval);
2383 break;
2384 case XPATH_USERS:
2385 case XPATH_POINT:
2386 case XPATH_RANGE:
2387 case XPATH_LOCATIONSET:
2388 TODO;
2389 break;
2390 }
2391 xmlXPathReleaseObject(ctxt, val);
2392 if (res == NULL)
2393 return(xmlXPathCacheNewCString(ctxt, ""));
2394 return(xmlXPathCacheWrapString(ctxt, res));
2395}
2396
2397/**
2398 * xmlXPathCacheObjectCopy:
2399 * @ctxt: the XPath context
2400 * @val: the original object
2401 *
2402 * This is the cached version of xmlXPathObjectCopy().
2403 * Acquire a copy of a given object
2404 *
2405 * Returns a created or reused created object.
2406 */
2407static xmlXPathObjectPtr
2408xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2409{
2410 if (val == NULL)
2411 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002412
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002413 if (XP_HAS_CACHE(ctxt)) {
2414 switch (val->type) {
2415 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002416 return(xmlXPathCacheWrapNodeSet(ctxt,
2417 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002418 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002419 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002420 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002421 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002422 case XPATH_NUMBER:
2423 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2424 default:
2425 break;
2426 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002427 }
2428 return(xmlXPathObjectCopy(val));
2429}
2430
2431/**
2432 * xmlXPathCacheConvertBoolean:
2433 * @ctxt: the XPath context
2434 * @val: an XPath object
2435 *
2436 * This is the cached version of xmlXPathConvertBoolean().
2437 * Converts an existing object to its boolean() equivalent
2438 *
2439 * Returns a created or reused object, the old one is freed (or the operation
2440 * is done directly on @val)
2441 */
2442static xmlXPathObjectPtr
2443xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2444 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002445
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002446 if (val == NULL)
2447 return(xmlXPathCacheNewBoolean(ctxt, 0));
2448 if (val->type == XPATH_BOOLEAN)
2449 return(val);
2450 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2451 xmlXPathReleaseObject(ctxt, val);
2452 return(ret);
2453}
2454
2455/**
2456 * xmlXPathCacheConvertNumber:
2457 * @ctxt: the XPath context
2458 * @val: an XPath object
2459 *
2460 * This is the cached version of xmlXPathConvertNumber().
2461 * Converts an existing object to its number() equivalent
2462 *
2463 * Returns a created or reused object, the old one is freed (or the operation
2464 * is done directly on @val)
2465 */
2466static xmlXPathObjectPtr
2467xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2468 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002469
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002470 if (val == NULL)
2471 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2472 if (val->type == XPATH_NUMBER)
2473 return(val);
2474 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2475 xmlXPathReleaseObject(ctxt, val);
2476 return(ret);
2477}
2478
2479/************************************************************************
2480 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002481 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002482 * *
2483 ************************************************************************/
2484
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002485/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002486 * xmlXPathSetFrame:
2487 * @ctxt: an XPath parser context
2488 *
2489 * Set the callee evaluation frame
2490 *
2491 * Returns the previous frame value to be restored once done
2492 */
2493static int
2494xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2495 int ret;
2496
2497 if (ctxt == NULL)
2498 return(0);
2499 ret = ctxt->valueFrame;
2500 ctxt->valueFrame = ctxt->valueNr;
2501 return(ret);
2502}
2503
2504/**
2505 * xmlXPathPopFrame:
2506 * @ctxt: an XPath parser context
2507 * @frame: the previous frame value
2508 *
2509 * Remove the callee evaluation frame
2510 */
2511static void
2512xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2513 if (ctxt == NULL)
2514 return;
2515 if (ctxt->valueNr < ctxt->valueFrame) {
2516 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2517 }
2518 ctxt->valueFrame = frame;
2519}
2520
2521/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002522 * valuePop:
2523 * @ctxt: an XPath evaluation context
2524 *
2525 * Pops the top XPath object from the value stack
2526 *
2527 * Returns the XPath object just removed
2528 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002529xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002530valuePop(xmlXPathParserContextPtr ctxt)
2531{
2532 xmlXPathObjectPtr ret;
2533
Daniel Veillarda82b1822004-11-08 16:24:57 +00002534 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002535 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002536
2537 if (ctxt->valueNr <= ctxt->valueFrame) {
2538 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2539 return (NULL);
2540 }
2541
Daniel Veillard1c732d22002-11-30 11:22:59 +00002542 ctxt->valueNr--;
2543 if (ctxt->valueNr > 0)
2544 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2545 else
2546 ctxt->value = NULL;
2547 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002548 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002549 return (ret);
2550}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002551/**
2552 * valuePush:
2553 * @ctxt: an XPath evaluation context
2554 * @value: the XPath object
2555 *
2556 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002557 *
2558 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002559 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002560int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002561valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2562{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002563 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002564 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002565 xmlXPathObjectPtr *tmp;
2566
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002567 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2568 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2569 ctxt->error = XPATH_MEMORY_ERROR;
2570 return (0);
2571 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002572 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2573 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002574 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002575 if (tmp == NULL) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002576 xmlXPathErrMemory(NULL, "pushing value\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08002577 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002578 return (0);
2579 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002580 ctxt->valueMax *= 2;
2581 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002582 }
2583 ctxt->valueTab[ctxt->valueNr] = value;
2584 ctxt->value = value;
2585 return (ctxt->valueNr++);
2586}
Owen Taylor3473f882001-02-23 17:55:21 +00002587
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002588/**
2589 * xmlXPathPopBoolean:
2590 * @ctxt: an XPath parser context
2591 *
2592 * Pops a boolean from the stack, handling conversion if needed.
2593 * Check error with #xmlXPathCheckError.
2594 *
2595 * Returns the boolean
2596 */
2597int
2598xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2599 xmlXPathObjectPtr obj;
2600 int ret;
2601
2602 obj = valuePop(ctxt);
2603 if (obj == NULL) {
2604 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2605 return(0);
2606 }
William M. Brack08171912003-12-29 02:52:11 +00002607 if (obj->type != XPATH_BOOLEAN)
2608 ret = xmlXPathCastToBoolean(obj);
2609 else
2610 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002611 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002612 return(ret);
2613}
2614
2615/**
2616 * xmlXPathPopNumber:
2617 * @ctxt: an XPath parser context
2618 *
2619 * Pops a number from the stack, handling conversion if needed.
2620 * Check error with #xmlXPathCheckError.
2621 *
2622 * Returns the number
2623 */
2624double
2625xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2626 xmlXPathObjectPtr obj;
2627 double ret;
2628
2629 obj = valuePop(ctxt);
2630 if (obj == NULL) {
2631 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2632 return(0);
2633 }
William M. Brack08171912003-12-29 02:52:11 +00002634 if (obj->type != XPATH_NUMBER)
2635 ret = xmlXPathCastToNumber(obj);
2636 else
2637 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002638 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002639 return(ret);
2640}
2641
2642/**
2643 * xmlXPathPopString:
2644 * @ctxt: an XPath parser context
2645 *
2646 * Pops a string from the stack, handling conversion if needed.
2647 * Check error with #xmlXPathCheckError.
2648 *
2649 * Returns the string
2650 */
2651xmlChar *
2652xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2653 xmlXPathObjectPtr obj;
2654 xmlChar * ret;
2655
2656 obj = valuePop(ctxt);
2657 if (obj == NULL) {
2658 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2659 return(NULL);
2660 }
William M. Brack08171912003-12-29 02:52:11 +00002661 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002662 /* TODO: needs refactoring somewhere else */
2663 if (obj->stringval == ret)
2664 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002665 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002666 return(ret);
2667}
2668
2669/**
2670 * xmlXPathPopNodeSet:
2671 * @ctxt: an XPath parser context
2672 *
2673 * Pops a node-set from the stack, handling conversion if needed.
2674 * Check error with #xmlXPathCheckError.
2675 *
2676 * Returns the node-set
2677 */
2678xmlNodeSetPtr
2679xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2680 xmlXPathObjectPtr obj;
2681 xmlNodeSetPtr ret;
2682
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002683 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002684 if (ctxt->value == NULL) {
2685 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2686 return(NULL);
2687 }
2688 if (!xmlXPathStackIsNodeSet(ctxt)) {
2689 xmlXPathSetTypeError(ctxt);
2690 return(NULL);
2691 }
2692 obj = valuePop(ctxt);
2693 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002694#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002695 /* to fix memory leak of not clearing obj->user */
2696 if (obj->boolval && obj->user != NULL)
2697 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002698#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002699 obj->nodesetval = NULL;
2700 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002701 return(ret);
2702}
2703
2704/**
2705 * xmlXPathPopExternal:
2706 * @ctxt: an XPath parser context
2707 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002708 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002709 * Check error with #xmlXPathCheckError.
2710 *
2711 * Returns the object
2712 */
2713void *
2714xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2715 xmlXPathObjectPtr obj;
2716 void * ret;
2717
Daniel Veillarda82b1822004-11-08 16:24:57 +00002718 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002719 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2720 return(NULL);
2721 }
2722 if (ctxt->value->type != XPATH_USERS) {
2723 xmlXPathSetTypeError(ctxt);
2724 return(NULL);
2725 }
2726 obj = valuePop(ctxt);
2727 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002728 obj->user = NULL;
2729 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002730 return(ret);
2731}
2732
Owen Taylor3473f882001-02-23 17:55:21 +00002733/*
2734 * Macros for accessing the content. Those should be used only by the parser,
2735 * and not exported.
2736 *
2737 * Dirty macros, i.e. one need to make assumption on the context to use them
2738 *
2739 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2740 * CUR returns the current xmlChar value, i.e. a 8 bit value
2741 * in ISO-Latin or UTF-8.
2742 * This should be used internally by the parser
2743 * only to compare to ASCII values otherwise it would break when
2744 * running with UTF-8 encoding.
2745 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2746 * to compare on ASCII based substring.
2747 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2748 * strings within the parser.
2749 * CURRENT Returns the current char value, with the full decoding of
2750 * UTF-8 if we are using this mode. It returns an int.
2751 * NEXT Skip to the next character, this does the proper decoding
2752 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2753 * It returns the pointer to the current xmlChar.
2754 */
2755
2756#define CUR (*ctxt->cur)
2757#define SKIP(val) ctxt->cur += (val)
2758#define NXT(val) ctxt->cur[(val)]
2759#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002760#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2761
2762#define COPY_BUF(l,b,i,v) \
2763 if (l == 1) b[i++] = (xmlChar) v; \
2764 else i += xmlCopyChar(l,&b[i],v)
2765
2766#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002767
Daniel Veillard45490ae2008-07-29 09:13:19 +00002768#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002769 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002770
2771#define CURRENT (*ctxt->cur)
2772#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2773
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002774
2775#ifndef DBL_DIG
2776#define DBL_DIG 16
2777#endif
2778#ifndef DBL_EPSILON
2779#define DBL_EPSILON 1E-9
2780#endif
2781
2782#define UPPER_DOUBLE 1E9
2783#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00002784#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002785
2786#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00002787#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002788#define EXPONENT_DIGITS (3 + 2)
2789
2790/**
2791 * xmlXPathFormatNumber:
2792 * @number: number to format
2793 * @buffer: output buffer
2794 * @buffersize: size of output buffer
2795 *
2796 * Convert the number into a string representation.
2797 */
2798static void
2799xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2800{
Daniel Veillardcda96922001-08-21 10:56:31 +00002801 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002802 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002803 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002804 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002805 break;
2806 case -1:
2807 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002808 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002809 break;
2810 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002811 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002812 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002813 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002814 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002815 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002816 } else if (number == ((int) number)) {
2817 char work[30];
2818 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002819 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002820
2821 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002822 if (value == 0) {
2823 *ptr++ = '0';
2824 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002825 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002826 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002827 while ((*cur) && (ptr - buffer < buffersize)) {
2828 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002829 }
2830 }
2831 if (ptr - buffer < buffersize) {
2832 *ptr = 0;
2833 } else if (buffersize > 0) {
2834 ptr--;
2835 *ptr = 0;
2836 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002837 } else {
William M. Brackca797882007-05-11 14:45:53 +00002838 /*
2839 For the dimension of work,
2840 DBL_DIG is number of significant digits
2841 EXPONENT is only needed for "scientific notation"
2842 3 is sign, decimal point, and terminating zero
2843 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2844 Note that this dimension is slightly (a few characters)
2845 larger than actually necessary.
2846 */
2847 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002848 int integer_place, fraction_place;
2849 char *ptr;
2850 char *after_fraction;
2851 double absolute_value;
2852 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002853
Bjorn Reese70a9da52001-04-21 16:57:29 +00002854 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002855
Bjorn Reese70a9da52001-04-21 16:57:29 +00002856 /*
2857 * First choose format - scientific or regular floating point.
2858 * In either case, result is in work, and after_fraction points
2859 * just past the fractional part.
2860 */
2861 if ( ((absolute_value > UPPER_DOUBLE) ||
2862 (absolute_value < LOWER_DOUBLE)) &&
2863 (absolute_value != 0.0) ) {
2864 /* Use scientific notation */
2865 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2866 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002867 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002868 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002869 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002870
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002871 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002872 else {
2873 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00002874 if (absolute_value > 0.0) {
2875 integer_place = (int)log10(absolute_value);
2876 if (integer_place > 0)
2877 fraction_place = DBL_DIG - integer_place - 1;
2878 else
2879 fraction_place = DBL_DIG - integer_place;
2880 } else {
2881 fraction_place = 1;
2882 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002883 size = snprintf(work, sizeof(work), "%0.*f",
2884 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002885 }
2886
Bjorn Reese70a9da52001-04-21 16:57:29 +00002887 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00002888 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002889 ptr = after_fraction;
2890 while (*(--ptr) == '0')
2891 ;
2892 if (*ptr != '.')
2893 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002894 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002895
2896 /* Finally copy result back to caller */
2897 size = strlen(work) + 1;
2898 if (size > buffersize) {
2899 work[buffersize - 1] = 0;
2900 size = buffersize;
2901 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002902 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002903 }
2904 break;
2905 }
2906}
2907
Owen Taylor3473f882001-02-23 17:55:21 +00002908
2909/************************************************************************
2910 * *
2911 * Routines to handle NodeSets *
2912 * *
2913 ************************************************************************/
2914
2915/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002916 * xmlXPathOrderDocElems:
2917 * @doc: an input document
2918 *
2919 * Call this routine to speed up XPath computation on static documents.
2920 * This stamps all the element nodes with the document order
2921 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002922 * field, the value stored is actually - the node number (starting at -1)
2923 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002924 *
William M. Brack08171912003-12-29 02:52:11 +00002925 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002926 * of error.
2927 */
2928long
2929xmlXPathOrderDocElems(xmlDocPtr doc) {
2930 long count = 0;
2931 xmlNodePtr cur;
2932
2933 if (doc == NULL)
2934 return(-1);
2935 cur = doc->children;
2936 while (cur != NULL) {
2937 if (cur->type == XML_ELEMENT_NODE) {
2938 cur->content = (void *) (-(++count));
2939 if (cur->children != NULL) {
2940 cur = cur->children;
2941 continue;
2942 }
2943 }
2944 if (cur->next != NULL) {
2945 cur = cur->next;
2946 continue;
2947 }
2948 do {
2949 cur = cur->parent;
2950 if (cur == NULL)
2951 break;
2952 if (cur == (xmlNodePtr) doc) {
2953 cur = NULL;
2954 break;
2955 }
2956 if (cur->next != NULL) {
2957 cur = cur->next;
2958 break;
2959 }
2960 } while (cur != NULL);
2961 }
2962 return(count);
2963}
2964
2965/**
Owen Taylor3473f882001-02-23 17:55:21 +00002966 * xmlXPathCmpNodes:
2967 * @node1: the first node
2968 * @node2: the second node
2969 *
2970 * Compare two nodes w.r.t document order
2971 *
2972 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002973 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002974 */
2975int
2976xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2977 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002978 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002979 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002980 xmlNodePtr cur, root;
2981
2982 if ((node1 == NULL) || (node2 == NULL))
2983 return(-2);
2984 /*
2985 * a couple of optimizations which will avoid computations in most cases
2986 */
William M. Brackee0b9822007-03-07 08:15:01 +00002987 if (node1 == node2) /* trivial case */
2988 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00002989 if (node1->type == XML_ATTRIBUTE_NODE) {
2990 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002991 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002992 node1 = node1->parent;
2993 }
2994 if (node2->type == XML_ATTRIBUTE_NODE) {
2995 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002996 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002997 node2 = node2->parent;
2998 }
2999 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00003000 if (attr1 == attr2) {
3001 /* not required, but we keep attributes in order */
3002 if (attr1 != 0) {
3003 cur = attrNode2->prev;
3004 while (cur != NULL) {
3005 if (cur == attrNode1)
3006 return (1);
3007 cur = cur->prev;
3008 }
3009 return (-1);
3010 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003011 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00003012 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003013 if (attr2 == 1)
3014 return(1);
3015 return(-1);
3016 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003017 if ((node1->type == XML_NAMESPACE_DECL) ||
3018 (node2->type == XML_NAMESPACE_DECL))
3019 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003020 if (node1 == node2->prev)
3021 return(1);
3022 if (node1 == node2->next)
3023 return(-1);
3024
3025 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003026 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003027 */
3028 if ((node1->type == XML_ELEMENT_NODE) &&
3029 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003030 (0 > (long) node1->content) &&
3031 (0 > (long) node2->content) &&
3032 (node1->doc == node2->doc)) {
3033 long l1, l2;
3034
3035 l1 = -((long) node1->content);
3036 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003037 if (l1 < l2)
3038 return(1);
3039 if (l1 > l2)
3040 return(-1);
3041 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003042
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003043 /*
Owen Taylor3473f882001-02-23 17:55:21 +00003044 * compute depth to root
3045 */
3046 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3047 if (cur == node1)
3048 return(1);
3049 depth2++;
3050 }
3051 root = cur;
3052 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3053 if (cur == node2)
3054 return(-1);
3055 depth1++;
3056 }
3057 /*
3058 * Distinct document (or distinct entities :-( ) case.
3059 */
3060 if (root != cur) {
3061 return(-2);
3062 }
3063 /*
3064 * get the nearest common ancestor.
3065 */
3066 while (depth1 > depth2) {
3067 depth1--;
3068 node1 = node1->parent;
3069 }
3070 while (depth2 > depth1) {
3071 depth2--;
3072 node2 = node2->parent;
3073 }
3074 while (node1->parent != node2->parent) {
3075 node1 = node1->parent;
3076 node2 = node2->parent;
3077 /* should not happen but just in case ... */
3078 if ((node1 == NULL) || (node2 == NULL))
3079 return(-2);
3080 }
3081 /*
3082 * Find who's first.
3083 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003084 if (node1 == node2->prev)
3085 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003086 if (node1 == node2->next)
3087 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003088 /*
3089 * Speedup using document order if availble.
3090 */
3091 if ((node1->type == XML_ELEMENT_NODE) &&
3092 (node2->type == XML_ELEMENT_NODE) &&
3093 (0 > (long) node1->content) &&
3094 (0 > (long) node2->content) &&
3095 (node1->doc == node2->doc)) {
3096 long l1, l2;
3097
3098 l1 = -((long) node1->content);
3099 l2 = -((long) node2->content);
3100 if (l1 < l2)
3101 return(1);
3102 if (l1 > l2)
3103 return(-1);
3104 }
3105
Owen Taylor3473f882001-02-23 17:55:21 +00003106 for (cur = node1->next;cur != NULL;cur = cur->next)
3107 if (cur == node2)
3108 return(1);
3109 return(-1); /* assume there is no sibling list corruption */
3110}
3111
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003112#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003113/**
3114 * xmlXPathCmpNodesExt:
3115 * @node1: the first node
3116 * @node2: the second node
3117 *
3118 * Compare two nodes w.r.t document order.
3119 * This one is optimized for handling of non-element nodes.
3120 *
3121 * Returns -2 in case of error 1 if first point < second point, 0 if
3122 * it's the same node, -1 otherwise
3123 */
3124static int
3125xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3126 int depth1, depth2;
3127 int misc = 0, precedence1 = 0, precedence2 = 0;
3128 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3129 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003130 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003131
3132 if ((node1 == NULL) || (node2 == NULL))
3133 return(-2);
3134
3135 if (node1 == node2)
3136 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00003137
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003138 /*
3139 * a couple of optimizations which will avoid computations in most cases
Daniel Veillard45490ae2008-07-29 09:13:19 +00003140 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003141 switch (node1->type) {
3142 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003143 if (node2->type == XML_ELEMENT_NODE) {
3144 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3145 (0 > (long) node2->content) &&
3146 (node1->doc == node2->doc))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003147 {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003148 l1 = -((long) node1->content);
3149 l2 = -((long) node2->content);
3150 if (l1 < l2)
3151 return(1);
3152 if (l1 > l2)
3153 return(-1);
3154 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003155 goto turtle_comparison;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003156 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003157 break;
3158 case XML_ATTRIBUTE_NODE:
3159 precedence1 = 1; /* element is owner */
3160 miscNode1 = node1;
3161 node1 = node1->parent;
3162 misc = 1;
3163 break;
3164 case XML_TEXT_NODE:
3165 case XML_CDATA_SECTION_NODE:
3166 case XML_COMMENT_NODE:
3167 case XML_PI_NODE: {
3168 miscNode1 = node1;
3169 /*
3170 * Find nearest element node.
Daniel Veillard45490ae2008-07-29 09:13:19 +00003171 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003172 if (node1->prev != NULL) {
3173 do {
3174 node1 = node1->prev;
3175 if (node1->type == XML_ELEMENT_NODE) {
3176 precedence1 = 3; /* element in prev-sibl axis */
3177 break;
3178 }
3179 if (node1->prev == NULL) {
3180 precedence1 = 2; /* element is parent */
3181 /*
3182 * URGENT TODO: Are there any cases, where the
3183 * parent of such a node is not an element node?
3184 */
3185 node1 = node1->parent;
3186 break;
3187 }
3188 } while (1);
3189 } else {
3190 precedence1 = 2; /* element is parent */
3191 node1 = node1->parent;
3192 }
William M. Brack31700e62007-06-13 20:33:02 +00003193 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3194 (0 <= (long) node1->content)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003195 /*
3196 * Fallback for whatever case.
3197 */
3198 node1 = miscNode1;
3199 precedence1 = 0;
3200 } else
3201 misc = 1;
3202 }
3203 break;
3204 case XML_NAMESPACE_DECL:
3205 /*
3206 * TODO: why do we return 1 for namespace nodes?
3207 */
3208 return(1);
3209 default:
3210 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003211 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003212 switch (node2->type) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003213 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003214 break;
3215 case XML_ATTRIBUTE_NODE:
3216 precedence2 = 1; /* element is owner */
3217 miscNode2 = node2;
3218 node2 = node2->parent;
3219 misc = 1;
3220 break;
3221 case XML_TEXT_NODE:
3222 case XML_CDATA_SECTION_NODE:
3223 case XML_COMMENT_NODE:
3224 case XML_PI_NODE: {
3225 miscNode2 = node2;
3226 if (node2->prev != NULL) {
3227 do {
3228 node2 = node2->prev;
3229 if (node2->type == XML_ELEMENT_NODE) {
3230 precedence2 = 3; /* element in prev-sibl axis */
3231 break;
3232 }
3233 if (node2->prev == NULL) {
3234 precedence2 = 2; /* element is parent */
3235 node2 = node2->parent;
3236 break;
3237 }
3238 } while (1);
3239 } else {
3240 precedence2 = 2; /* element is parent */
3241 node2 = node2->parent;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003242 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003243 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3244 (0 <= (long) node1->content))
3245 {
3246 node2 = miscNode2;
3247 precedence2 = 0;
3248 } else
3249 misc = 1;
3250 }
3251 break;
3252 case XML_NAMESPACE_DECL:
3253 return(1);
3254 default:
3255 break;
3256 }
3257 if (misc) {
3258 if (node1 == node2) {
3259 if (precedence1 == precedence2) {
3260 /*
3261 * The ugly case; but normally there aren't many
3262 * adjacent non-element nodes around.
3263 */
3264 cur = miscNode2->prev;
3265 while (cur != NULL) {
3266 if (cur == miscNode1)
3267 return(1);
3268 if (cur->type == XML_ELEMENT_NODE)
3269 return(-1);
3270 cur = cur->prev;
3271 }
3272 return (-1);
3273 } else {
3274 /*
3275 * Evaluate based on higher precedence wrt to the element.
3276 * TODO: This assumes attributes are sorted before content.
3277 * Is this 100% correct?
3278 */
3279 if (precedence1 < precedence2)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003280 return(1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003281 else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003282 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003283 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003284 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003285 /*
3286 * Special case: One of the helper-elements is contained by the other.
3287 * <foo>
3288 * <node2>
3289 * <node1>Text-1(precedence1 == 2)</node1>
3290 * </node2>
3291 * Text-6(precedence2 == 3)
3292 * </foo>
Daniel Veillard45490ae2008-07-29 09:13:19 +00003293 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003294 if ((precedence2 == 3) && (precedence1 > 1)) {
3295 cur = node1->parent;
3296 while (cur) {
3297 if (cur == node2)
3298 return(1);
3299 cur = cur->parent;
3300 }
3301 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003302 if ((precedence1 == 3) && (precedence2 > 1)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003303 cur = node2->parent;
3304 while (cur) {
3305 if (cur == node1)
3306 return(-1);
3307 cur = cur->parent;
3308 }
3309 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003310 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003311
3312 /*
3313 * Speedup using document order if availble.
3314 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003315 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003316 (node2->type == XML_ELEMENT_NODE) &&
3317 (0 > (long) node1->content) &&
3318 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003319 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003320
3321 l1 = -((long) node1->content);
3322 l2 = -((long) node2->content);
3323 if (l1 < l2)
3324 return(1);
3325 if (l1 > l2)
3326 return(-1);
3327 }
3328
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003329turtle_comparison:
3330
3331 if (node1 == node2->prev)
3332 return(1);
3333 if (node1 == node2->next)
3334 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003335 /*
3336 * compute depth to root
3337 */
3338 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3339 if (cur == node1)
3340 return(1);
3341 depth2++;
3342 }
3343 root = cur;
3344 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3345 if (cur == node2)
3346 return(-1);
3347 depth1++;
3348 }
3349 /*
3350 * Distinct document (or distinct entities :-( ) case.
3351 */
3352 if (root != cur) {
3353 return(-2);
3354 }
3355 /*
3356 * get the nearest common ancestor.
3357 */
3358 while (depth1 > depth2) {
3359 depth1--;
3360 node1 = node1->parent;
3361 }
3362 while (depth2 > depth1) {
3363 depth2--;
3364 node2 = node2->parent;
3365 }
3366 while (node1->parent != node2->parent) {
3367 node1 = node1->parent;
3368 node2 = node2->parent;
3369 /* should not happen but just in case ... */
3370 if ((node1 == NULL) || (node2 == NULL))
3371 return(-2);
3372 }
3373 /*
3374 * Find who's first.
3375 */
3376 if (node1 == node2->prev)
3377 return(1);
3378 if (node1 == node2->next)
3379 return(-1);
3380 /*
3381 * Speedup using document order if availble.
3382 */
3383 if ((node1->type == XML_ELEMENT_NODE) &&
3384 (node2->type == XML_ELEMENT_NODE) &&
3385 (0 > (long) node1->content) &&
3386 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003387 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003388
3389 l1 = -((long) node1->content);
3390 l2 = -((long) node2->content);
3391 if (l1 < l2)
3392 return(1);
3393 if (l1 > l2)
3394 return(-1);
3395 }
3396
3397 for (cur = node1->next;cur != NULL;cur = cur->next)
3398 if (cur == node2)
3399 return(1);
3400 return(-1); /* assume there is no sibling list corruption */
3401}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003402#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003403
Owen Taylor3473f882001-02-23 17:55:21 +00003404/**
3405 * xmlXPathNodeSetSort:
3406 * @set: the node set
3407 *
3408 * Sort the node set in document order
3409 */
3410void
3411xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Vojtech Fried3e031b72012-08-24 16:52:44 +08003412#ifndef WITH_TIM_SORT
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003413 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003414 xmlNodePtr tmp;
Vojtech Fried3e031b72012-08-24 16:52:44 +08003415#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003416
3417 if (set == NULL)
3418 return;
3419
Vojtech Fried3e031b72012-08-24 16:52:44 +08003420#ifndef WITH_TIM_SORT
3421 /*
3422 * Use the old Shell's sort implementation to sort the node-set
3423 * Timsort ought to be quite faster
3424 */
Owen Taylor3473f882001-02-23 17:55:21 +00003425 len = set->nodeNr;
3426 for (incr = len / 2; incr > 0; incr /= 2) {
3427 for (i = incr; i < len; i++) {
3428 j = i - incr;
3429 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003430#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003431 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3432 set->nodeTab[j + incr]) == -1)
3433#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003434 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003435 set->nodeTab[j + incr]) == -1)
3436#endif
3437 {
Owen Taylor3473f882001-02-23 17:55:21 +00003438 tmp = set->nodeTab[j];
3439 set->nodeTab[j] = set->nodeTab[j + incr];
3440 set->nodeTab[j + incr] = tmp;
3441 j -= incr;
3442 } else
3443 break;
3444 }
3445 }
3446 }
Vojtech Fried3e031b72012-08-24 16:52:44 +08003447#else /* WITH_TIM_SORT */
3448 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3449#endif /* WITH_TIM_SORT */
Owen Taylor3473f882001-02-23 17:55:21 +00003450}
3451
3452#define XML_NODESET_DEFAULT 10
3453/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003454 * xmlXPathNodeSetDupNs:
3455 * @node: the parent node of the namespace XPath node
3456 * @ns: the libxml namespace declaration node.
3457 *
3458 * Namespace node in libxml don't match the XPath semantic. In a node set
3459 * the namespace nodes are duplicated and the next pointer is set to the
3460 * parent node in the XPath semantic.
3461 *
3462 * Returns the newly created object.
3463 */
3464static xmlNodePtr
3465xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3466 xmlNsPtr cur;
3467
3468 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3469 return(NULL);
3470 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3471 return((xmlNodePtr) ns);
3472
3473 /*
3474 * Allocate a new Namespace and fill the fields.
3475 */
3476 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3477 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003478 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003479 return(NULL);
3480 }
3481 memset(cur, 0, sizeof(xmlNs));
3482 cur->type = XML_NAMESPACE_DECL;
3483 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003484 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003485 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003486 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003487 cur->next = (xmlNsPtr) node;
3488 return((xmlNodePtr) cur);
3489}
3490
3491/**
3492 * xmlXPathNodeSetFreeNs:
3493 * @ns: the XPath namespace node found in a nodeset.
3494 *
William M. Brack08171912003-12-29 02:52:11 +00003495 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003496 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003497 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003498 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003499void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003500xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3501 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3502 return;
3503
3504 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3505 if (ns->href != NULL)
3506 xmlFree((xmlChar *)ns->href);
3507 if (ns->prefix != NULL)
3508 xmlFree((xmlChar *)ns->prefix);
3509 xmlFree(ns);
3510 }
3511}
3512
3513/**
Owen Taylor3473f882001-02-23 17:55:21 +00003514 * xmlXPathNodeSetCreate:
3515 * @val: an initial xmlNodePtr, or NULL
3516 *
3517 * Create a new xmlNodeSetPtr of type double and of value @val
3518 *
3519 * Returns the newly created object.
3520 */
3521xmlNodeSetPtr
3522xmlXPathNodeSetCreate(xmlNodePtr val) {
3523 xmlNodeSetPtr ret;
3524
3525 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3526 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003527 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003528 return(NULL);
3529 }
3530 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3531 if (val != NULL) {
3532 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3533 sizeof(xmlNodePtr));
3534 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003535 xmlXPathErrMemory(NULL, "creating nodeset\n");
3536 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003537 return(NULL);
3538 }
3539 memset(ret->nodeTab, 0 ,
3540 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3541 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003542 if (val->type == XML_NAMESPACE_DECL) {
3543 xmlNsPtr ns = (xmlNsPtr) val;
3544
3545 ret->nodeTab[ret->nodeNr++] =
3546 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3547 } else
3548 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003549 }
3550 return(ret);
3551}
3552
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003553/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003554 * xmlXPathNodeSetCreateSize:
3555 * @size: the initial size of the set
3556 *
3557 * Create a new xmlNodeSetPtr of type double and of value @val
3558 *
3559 * Returns the newly created object.
3560 */
3561static xmlNodeSetPtr
3562xmlXPathNodeSetCreateSize(int size) {
3563 xmlNodeSetPtr ret;
3564
3565 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3566 if (ret == NULL) {
3567 xmlXPathErrMemory(NULL, "creating nodeset\n");
3568 return(NULL);
3569 }
3570 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3571 if (size < XML_NODESET_DEFAULT)
3572 size = XML_NODESET_DEFAULT;
3573 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3574 if (ret->nodeTab == NULL) {
3575 xmlXPathErrMemory(NULL, "creating nodeset\n");
3576 xmlFree(ret);
3577 return(NULL);
3578 }
3579 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003580 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003581 return(ret);
3582}
3583
3584/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003585 * xmlXPathNodeSetContains:
3586 * @cur: the node-set
3587 * @val: the node
3588 *
3589 * checks whether @cur contains @val
3590 *
3591 * Returns true (1) if @cur contains @val, false (0) otherwise
3592 */
3593int
3594xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3595 int i;
3596
Daniel Veillarda82b1822004-11-08 16:24:57 +00003597 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003598 if (val->type == XML_NAMESPACE_DECL) {
3599 for (i = 0; i < cur->nodeNr; i++) {
3600 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3601 xmlNsPtr ns1, ns2;
3602
3603 ns1 = (xmlNsPtr) val;
3604 ns2 = (xmlNsPtr) cur->nodeTab[i];
3605 if (ns1 == ns2)
3606 return(1);
3607 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3608 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3609 return(1);
3610 }
3611 }
3612 } else {
3613 for (i = 0; i < cur->nodeNr; i++) {
3614 if (cur->nodeTab[i] == val)
3615 return(1);
3616 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003617 }
3618 return(0);
3619}
3620
3621/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003622 * xmlXPathNodeSetAddNs:
3623 * @cur: the initial node set
3624 * @node: the hosting node
3625 * @ns: a the namespace node
3626 *
3627 * add a new namespace node to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003628 *
3629 * Returns 0 in case of success and -1 in case of error
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003630 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003631int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003632xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3633 int i;
3634
Daniel Veillard45490ae2008-07-29 09:13:19 +00003635
Daniel Veillarda82b1822004-11-08 16:24:57 +00003636 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3637 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003638 (node->type != XML_ELEMENT_NODE))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003639 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003640
William M. Brack08171912003-12-29 02:52:11 +00003641 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003642 /*
William M. Brack08171912003-12-29 02:52:11 +00003643 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003644 */
3645 for (i = 0;i < cur->nodeNr;i++) {
3646 if ((cur->nodeTab[i] != NULL) &&
3647 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003648 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003649 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003650 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003651 }
3652
3653 /*
3654 * grow the nodeTab if needed
3655 */
3656 if (cur->nodeMax == 0) {
3657 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3658 sizeof(xmlNodePtr));
3659 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003660 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003661 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003662 }
3663 memset(cur->nodeTab, 0 ,
3664 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3665 cur->nodeMax = XML_NODESET_DEFAULT;
3666 } else if (cur->nodeNr == cur->nodeMax) {
3667 xmlNodePtr *temp;
3668
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003669 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3670 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003671 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003672 }
Chris Evansd7958b22011-03-23 08:13:06 +08003673 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003674 sizeof(xmlNodePtr));
3675 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003676 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003677 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003678 }
Chris Evansd7958b22011-03-23 08:13:06 +08003679 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003680 cur->nodeTab = temp;
3681 }
3682 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003683 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003684}
3685
3686/**
Owen Taylor3473f882001-02-23 17:55:21 +00003687 * xmlXPathNodeSetAdd:
3688 * @cur: the initial node set
3689 * @val: a new xmlNodePtr
3690 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003691 * add a new xmlNodePtr to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003692 *
3693 * Returns 0 in case of success, and -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00003694 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003695int
Owen Taylor3473f882001-02-23 17:55:21 +00003696xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3697 int i;
3698
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003699 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003700
William M. Brack08171912003-12-29 02:52:11 +00003701 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003702 /*
William M. Brack08171912003-12-29 02:52:11 +00003703 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003704 */
3705 for (i = 0;i < cur->nodeNr;i++)
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003706 if (cur->nodeTab[i] == val) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003707
3708 /*
3709 * grow the nodeTab if needed
3710 */
3711 if (cur->nodeMax == 0) {
3712 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3713 sizeof(xmlNodePtr));
3714 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003715 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003716 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003717 }
3718 memset(cur->nodeTab, 0 ,
3719 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3720 cur->nodeMax = XML_NODESET_DEFAULT;
3721 } else if (cur->nodeNr == cur->nodeMax) {
3722 xmlNodePtr *temp;
3723
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003724 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3725 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003726 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003727 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003728 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003729 sizeof(xmlNodePtr));
3730 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003731 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003732 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003733 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003734 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003735 cur->nodeTab = temp;
3736 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003737 if (val->type == XML_NAMESPACE_DECL) {
3738 xmlNsPtr ns = (xmlNsPtr) val;
3739
Daniel Veillard45490ae2008-07-29 09:13:19 +00003740 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003741 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3742 } else
3743 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003744 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003745}
3746
3747/**
3748 * xmlXPathNodeSetAddUnique:
3749 * @cur: the initial node set
3750 * @val: a new xmlNodePtr
3751 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003752 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003753 * when we are sure the node is not already in the set.
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003754 *
3755 * Returns 0 in case of success and -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00003756 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003757int
Owen Taylor3473f882001-02-23 17:55:21 +00003758xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003759 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003760
William M. Brack08171912003-12-29 02:52:11 +00003761 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003762 /*
3763 * grow the nodeTab if needed
3764 */
3765 if (cur->nodeMax == 0) {
3766 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3767 sizeof(xmlNodePtr));
3768 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003769 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003770 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003771 }
3772 memset(cur->nodeTab, 0 ,
3773 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3774 cur->nodeMax = XML_NODESET_DEFAULT;
3775 } else if (cur->nodeNr == cur->nodeMax) {
3776 xmlNodePtr *temp;
3777
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003778 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3779 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003780 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003781 }
Chris Evansd7958b22011-03-23 08:13:06 +08003782 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003783 sizeof(xmlNodePtr));
3784 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003785 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003786 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003787 }
3788 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003789 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003790 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003791 if (val->type == XML_NAMESPACE_DECL) {
3792 xmlNsPtr ns = (xmlNsPtr) val;
3793
Daniel Veillard45490ae2008-07-29 09:13:19 +00003794 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003795 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3796 } else
3797 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003798 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003799}
3800
3801/**
3802 * xmlXPathNodeSetMerge:
3803 * @val1: the first NodeSet or NULL
3804 * @val2: the second NodeSet
3805 *
3806 * Merges two nodesets, all nodes from @val2 are added to @val1
3807 * if @val1 is NULL, a new set is created and copied from @val2
3808 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003809 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003810 */
3811xmlNodeSetPtr
3812xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003813 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003814 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003815
3816 if (val2 == NULL) return(val1);
3817 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003818 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003819 if (val1 == NULL)
3820 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003821#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003822 /*
3823 * TODO: The optimization won't work in every case, since
3824 * those nasty namespace nodes need to be added with
3825 * xmlXPathNodeSetDupNs() to the set; thus a pure
3826 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003827 * If there was a flag on the nodesetval, indicating that
3828 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003829 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003830 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003831 * Optimization: Create an equally sized node-set
3832 * and memcpy the content.
3833 */
3834 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3835 if (val1 == NULL)
3836 return(NULL);
3837 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003838 if (val2->nodeNr == 1)
3839 *(val1->nodeTab) = *(val2->nodeTab);
3840 else {
3841 memcpy(val1->nodeTab, val2->nodeTab,
3842 val2->nodeNr * sizeof(xmlNodePtr));
3843 }
3844 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003845 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003846 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003847#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003848 }
3849
William M. Brack08171912003-12-29 02:52:11 +00003850 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003851 initNr = val1->nodeNr;
3852
3853 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003854 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003855 /*
William M. Brack08171912003-12-29 02:52:11 +00003856 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003857 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003858 skip = 0;
3859 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003860 n1 = val1->nodeTab[j];
3861 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003862 skip = 1;
3863 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003864 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003865 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003866 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3867 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3868 ((xmlNsPtr) n2)->prefix)))
3869 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003870 skip = 1;
3871 break;
3872 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003873 }
3874 }
3875 if (skip)
3876 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003877
3878 /*
3879 * grow the nodeTab if needed
3880 */
3881 if (val1->nodeMax == 0) {
3882 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3883 sizeof(xmlNodePtr));
3884 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003885 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003886 return(NULL);
3887 }
3888 memset(val1->nodeTab, 0 ,
3889 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3890 val1->nodeMax = XML_NODESET_DEFAULT;
3891 } else if (val1->nodeNr == val1->nodeMax) {
3892 xmlNodePtr *temp;
3893
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003894 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3895 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3896 return(NULL);
3897 }
Chris Evansd7958b22011-03-23 08:13:06 +08003898 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003899 sizeof(xmlNodePtr));
3900 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003901 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003902 return(NULL);
3903 }
3904 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003905 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003906 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003907 if (n2->type == XML_NAMESPACE_DECL) {
3908 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003909
3910 val1->nodeTab[val1->nodeNr++] =
3911 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3912 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003913 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003914 }
3915
3916 return(val1);
3917}
3918
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003919
3920/**
3921 * xmlXPathNodeSetMergeAndClear:
3922 * @set1: the first NodeSet or NULL
3923 * @set2: the second NodeSet
3924 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3925 *
3926 * Merges two nodesets, all nodes from @set2 are added to @set1
3927 * if @set1 is NULL, a new set is created and copied from @set2.
3928 * Checks for duplicate nodes. Clears set2.
3929 *
3930 * Returns @set1 once extended or NULL in case of error.
3931 */
3932static xmlNodeSetPtr
3933xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3934 int hasNullEntries)
3935{
3936 if ((set1 == NULL) && (hasNullEntries == 0)) {
3937 /*
3938 * Note that doing a memcpy of the list, namespace nodes are
3939 * just assigned to set1, since set2 is cleared anyway.
3940 */
3941 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3942 if (set1 == NULL)
3943 return(NULL);
3944 if (set2->nodeNr != 0) {
3945 memcpy(set1->nodeTab, set2->nodeTab,
3946 set2->nodeNr * sizeof(xmlNodePtr));
3947 set1->nodeNr = set2->nodeNr;
3948 }
3949 } else {
3950 int i, j, initNbSet1;
3951 xmlNodePtr n1, n2;
3952
3953 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003954 set1 = xmlXPathNodeSetCreate(NULL);
3955 if (set1 == NULL)
3956 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003957
Daniel Veillard45490ae2008-07-29 09:13:19 +00003958 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003959 for (i = 0;i < set2->nodeNr;i++) {
3960 n2 = set2->nodeTab[i];
3961 /*
3962 * Skip NULLed entries.
3963 */
3964 if (n2 == NULL)
3965 continue;
3966 /*
3967 * Skip duplicates.
3968 */
3969 for (j = 0; j < initNbSet1; j++) {
3970 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003971 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003972 goto skip_node;
3973 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3974 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003975 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003976 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3977 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3978 ((xmlNsPtr) n2)->prefix)))
3979 {
3980 /*
3981 * Free the namespace node.
3982 */
3983 set2->nodeTab[i] = NULL;
3984 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3985 goto skip_node;
3986 }
3987 }
3988 }
3989 /*
3990 * grow the nodeTab if needed
3991 */
3992 if (set1->nodeMax == 0) {
3993 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3994 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3995 if (set1->nodeTab == NULL) {
3996 xmlXPathErrMemory(NULL, "merging nodeset\n");
3997 return(NULL);
3998 }
3999 memset(set1->nodeTab, 0,
4000 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4001 set1->nodeMax = XML_NODESET_DEFAULT;
4002 } else if (set1->nodeNr >= set1->nodeMax) {
4003 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004004
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004005 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4006 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4007 return(NULL);
4008 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004009 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004010 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004011 if (temp == NULL) {
4012 xmlXPathErrMemory(NULL, "merging nodeset\n");
4013 return(NULL);
4014 }
4015 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004016 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004017 }
4018 if (n2->type == XML_NAMESPACE_DECL) {
4019 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004020
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004021 set1->nodeTab[set1->nodeNr++] =
4022 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
4023 } else
4024 set1->nodeTab[set1->nodeNr++] = n2;
4025skip_node:
4026 {}
4027 }
4028 }
4029 set2->nodeNr = 0;
4030 return(set1);
4031}
4032
4033/**
4034 * xmlXPathNodeSetMergeAndClearNoDupls:
4035 * @set1: the first NodeSet or NULL
4036 * @set2: the second NodeSet
4037 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4038 *
4039 * Merges two nodesets, all nodes from @set2 are added to @set1
4040 * if @set1 is NULL, a new set is created and copied from @set2.
4041 * Doesn't chack for duplicate nodes. Clears set2.
4042 *
4043 * Returns @set1 once extended or NULL in case of error.
4044 */
4045static xmlNodeSetPtr
4046xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4047 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004048{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004049 if (set2 == NULL)
4050 return(set1);
4051 if ((set1 == NULL) && (hasNullEntries == 0)) {
4052 /*
4053 * Note that doing a memcpy of the list, namespace nodes are
4054 * just assigned to set1, since set2 is cleared anyway.
4055 */
4056 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4057 if (set1 == NULL)
4058 return(NULL);
4059 if (set2->nodeNr != 0) {
4060 memcpy(set1->nodeTab, set2->nodeTab,
4061 set2->nodeNr * sizeof(xmlNodePtr));
4062 set1->nodeNr = set2->nodeNr;
4063 }
4064 } else {
4065 int i;
4066 xmlNodePtr n2;
4067
4068 if (set1 == NULL)
4069 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004070 if (set1 == NULL)
4071 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004072
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004073 for (i = 0;i < set2->nodeNr;i++) {
4074 n2 = set2->nodeTab[i];
4075 /*
4076 * Skip NULLed entries.
4077 */
4078 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004079 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004080 if (set1->nodeMax == 0) {
4081 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4082 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4083 if (set1->nodeTab == NULL) {
4084 xmlXPathErrMemory(NULL, "merging nodeset\n");
4085 return(NULL);
4086 }
4087 memset(set1->nodeTab, 0,
4088 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4089 set1->nodeMax = XML_NODESET_DEFAULT;
4090 } else if (set1->nodeNr >= set1->nodeMax) {
4091 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004092
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004093 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4094 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4095 return(NULL);
4096 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004097 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004098 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004099 if (temp == NULL) {
4100 xmlXPathErrMemory(NULL, "merging nodeset\n");
4101 return(NULL);
4102 }
4103 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004104 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004105 }
4106 set1->nodeTab[set1->nodeNr++] = n2;
4107 }
4108 }
4109 set2->nodeNr = 0;
4110 return(set1);
4111}
Daniel Veillard75be0132002-03-13 10:03:35 +00004112
4113/**
Owen Taylor3473f882001-02-23 17:55:21 +00004114 * xmlXPathNodeSetDel:
4115 * @cur: the initial node set
4116 * @val: an xmlNodePtr
4117 *
4118 * Removes an xmlNodePtr from an existing NodeSet
4119 */
4120void
4121xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4122 int i;
4123
4124 if (cur == NULL) return;
4125 if (val == NULL) return;
4126
4127 /*
William M. Brack08171912003-12-29 02:52:11 +00004128 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004129 */
4130 for (i = 0;i < cur->nodeNr;i++)
4131 if (cur->nodeTab[i] == val) break;
4132
William M. Brack08171912003-12-29 02:52:11 +00004133 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004134#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004135 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004136 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4137 val->name);
4138#endif
4139 return;
4140 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004141 if ((cur->nodeTab[i] != NULL) &&
4142 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4143 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004144 cur->nodeNr--;
4145 for (;i < cur->nodeNr;i++)
4146 cur->nodeTab[i] = cur->nodeTab[i + 1];
4147 cur->nodeTab[cur->nodeNr] = NULL;
4148}
4149
4150/**
4151 * xmlXPathNodeSetRemove:
4152 * @cur: the initial node set
4153 * @val: the index to remove
4154 *
4155 * Removes an entry from an existing NodeSet list.
4156 */
4157void
4158xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4159 if (cur == NULL) return;
4160 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004161 if ((cur->nodeTab[val] != NULL) &&
4162 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4163 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004164 cur->nodeNr--;
4165 for (;val < cur->nodeNr;val++)
4166 cur->nodeTab[val] = cur->nodeTab[val + 1];
4167 cur->nodeTab[cur->nodeNr] = NULL;
4168}
4169
4170/**
4171 * xmlXPathFreeNodeSet:
4172 * @obj: the xmlNodeSetPtr to free
4173 *
4174 * Free the NodeSet compound (not the actual nodes !).
4175 */
4176void
4177xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4178 if (obj == NULL) return;
4179 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004180 int i;
4181
William M. Brack08171912003-12-29 02:52:11 +00004182 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004183 for (i = 0;i < obj->nodeNr;i++)
4184 if ((obj->nodeTab[i] != NULL) &&
4185 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4186 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004187 xmlFree(obj->nodeTab);
4188 }
Owen Taylor3473f882001-02-23 17:55:21 +00004189 xmlFree(obj);
4190}
4191
4192/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004193 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004194 * @set: the node set to clear
Daniel Veillard45490ae2008-07-29 09:13:19 +00004195 *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004196 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4197 * are feed), but does *not* free the list itself. Sets the length of the
4198 * list to 0.
4199 */
4200static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004201xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4202{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004203 if ((set == NULL) || (set->nodeNr <= 0))
4204 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004205 else if (hasNsNodes) {
4206 int i;
4207 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004208
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004209 for (i = 0; i < set->nodeNr; i++) {
4210 node = set->nodeTab[i];
4211 if ((node != NULL) &&
4212 (node->type == XML_NAMESPACE_DECL))
4213 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004214 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004215 }
4216 set->nodeNr = 0;
4217}
4218
4219/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004220 * xmlXPathNodeSetClearFromPos:
4221 * @set: the node set to be cleared
4222 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004223 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004224 * Clears the list from temporary XPath objects (e.g. namespace nodes
4225 * are feed) starting with the entry at @pos, but does *not* free the list
4226 * itself. Sets the length of the list to @pos.
4227 */
4228static void
4229xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4230{
4231 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4232 return;
4233 else if ((hasNsNodes)) {
4234 int i;
4235 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004236
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004237 for (i = pos; i < set->nodeNr; i++) {
4238 node = set->nodeTab[i];
4239 if ((node != NULL) &&
4240 (node->type == XML_NAMESPACE_DECL))
4241 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004242 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004243 }
4244 set->nodeNr = pos;
4245}
4246
4247/**
Owen Taylor3473f882001-02-23 17:55:21 +00004248 * xmlXPathFreeValueTree:
4249 * @obj: the xmlNodeSetPtr to free
4250 *
4251 * Free the NodeSet compound and the actual tree, this is different
4252 * from xmlXPathFreeNodeSet()
4253 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004254static void
Owen Taylor3473f882001-02-23 17:55:21 +00004255xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4256 int i;
4257
4258 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004259
4260 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004261 for (i = 0;i < obj->nodeNr;i++) {
4262 if (obj->nodeTab[i] != NULL) {
4263 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4264 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4265 } else {
4266 xmlFreeNodeList(obj->nodeTab[i]);
4267 }
4268 }
4269 }
Owen Taylor3473f882001-02-23 17:55:21 +00004270 xmlFree(obj->nodeTab);
4271 }
Owen Taylor3473f882001-02-23 17:55:21 +00004272 xmlFree(obj);
4273}
4274
4275#if defined(DEBUG) || defined(DEBUG_STEP)
4276/**
4277 * xmlGenericErrorContextNodeSet:
4278 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004279 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004280 *
4281 * Quick display of a NodeSet
4282 */
4283void
4284xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4285 int i;
4286
4287 if (output == NULL) output = xmlGenericErrorContext;
4288 if (obj == NULL) {
4289 fprintf(output, "NodeSet == NULL !\n");
4290 return;
4291 }
4292 if (obj->nodeNr == 0) {
4293 fprintf(output, "NodeSet is empty\n");
4294 return;
4295 }
4296 if (obj->nodeTab == NULL) {
4297 fprintf(output, " nodeTab == NULL !\n");
4298 return;
4299 }
4300 for (i = 0; i < obj->nodeNr; i++) {
4301 if (obj->nodeTab[i] == NULL) {
4302 fprintf(output, " NULL !\n");
4303 return;
4304 }
4305 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4306 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4307 fprintf(output, " /");
4308 else if (obj->nodeTab[i]->name == NULL)
4309 fprintf(output, " noname!");
4310 else fprintf(output, " %s", obj->nodeTab[i]->name);
4311 }
4312 fprintf(output, "\n");
4313}
4314#endif
4315
4316/**
4317 * xmlXPathNewNodeSet:
4318 * @val: the NodePtr value
4319 *
4320 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4321 * it with the single Node @val
4322 *
4323 * Returns the newly created object.
4324 */
4325xmlXPathObjectPtr
4326xmlXPathNewNodeSet(xmlNodePtr val) {
4327 xmlXPathObjectPtr ret;
4328
4329 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4330 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004331 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004332 return(NULL);
4333 }
4334 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4335 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004336 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004337 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004338 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004339#ifdef XP_DEBUG_OBJ_USAGE
4340 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4341#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004342 return(ret);
4343}
4344
4345/**
4346 * xmlXPathNewValueTree:
4347 * @val: the NodePtr value
4348 *
4349 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4350 * it with the tree root @val
4351 *
4352 * Returns the newly created object.
4353 */
4354xmlXPathObjectPtr
4355xmlXPathNewValueTree(xmlNodePtr val) {
4356 xmlXPathObjectPtr ret;
4357
4358 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4359 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004360 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004361 return(NULL);
4362 }
4363 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4364 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004365 ret->boolval = 1;
4366 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004367 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004368#ifdef XP_DEBUG_OBJ_USAGE
4369 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4370#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004371 return(ret);
4372}
4373
4374/**
4375 * xmlXPathNewNodeSetList:
4376 * @val: an existing NodeSet
4377 *
4378 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4379 * it with the Nodeset @val
4380 *
4381 * Returns the newly created object.
4382 */
4383xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004384xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4385{
Owen Taylor3473f882001-02-23 17:55:21 +00004386 xmlXPathObjectPtr ret;
4387 int i;
4388
4389 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004390 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004391 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004392 ret = xmlXPathNewNodeSet(NULL);
4393 else {
4394 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004395 if (ret) {
4396 for (i = 1; i < val->nodeNr; ++i) {
4397 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4398 < 0) break;
4399 }
4400 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004401 }
Owen Taylor3473f882001-02-23 17:55:21 +00004402
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004403 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004404}
4405
4406/**
4407 * xmlXPathWrapNodeSet:
4408 * @val: the NodePtr value
4409 *
4410 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4411 *
4412 * Returns the newly created object.
4413 */
4414xmlXPathObjectPtr
4415xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4416 xmlXPathObjectPtr ret;
4417
4418 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4419 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004420 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004421 return(NULL);
4422 }
4423 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4424 ret->type = XPATH_NODESET;
4425 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004426#ifdef XP_DEBUG_OBJ_USAGE
4427 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4428#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004429 return(ret);
4430}
4431
4432/**
4433 * xmlXPathFreeNodeSetList:
4434 * @obj: an existing NodeSetList object
4435 *
4436 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4437 * the list contrary to xmlXPathFreeObject().
4438 */
4439void
4440xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4441 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004442#ifdef XP_DEBUG_OBJ_USAGE
4443 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4444#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004445 xmlFree(obj);
4446}
4447
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004448/**
4449 * xmlXPathDifference:
4450 * @nodes1: a node-set
4451 * @nodes2: a node-set
4452 *
4453 * Implements the EXSLT - Sets difference() function:
4454 * node-set set:difference (node-set, node-set)
4455 *
4456 * Returns the difference between the two node sets, or nodes1 if
4457 * nodes2 is empty
4458 */
4459xmlNodeSetPtr
4460xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4461 xmlNodeSetPtr ret;
4462 int i, l1;
4463 xmlNodePtr cur;
4464
4465 if (xmlXPathNodeSetIsEmpty(nodes2))
4466 return(nodes1);
4467
4468 ret = xmlXPathNodeSetCreate(NULL);
4469 if (xmlXPathNodeSetIsEmpty(nodes1))
4470 return(ret);
4471
4472 l1 = xmlXPathNodeSetGetLength(nodes1);
4473
4474 for (i = 0; i < l1; i++) {
4475 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004476 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4477 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4478 break;
4479 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004480 }
4481 return(ret);
4482}
4483
4484/**
4485 * xmlXPathIntersection:
4486 * @nodes1: a node-set
4487 * @nodes2: a node-set
4488 *
4489 * Implements the EXSLT - Sets intersection() function:
4490 * node-set set:intersection (node-set, node-set)
4491 *
4492 * Returns a node set comprising the nodes that are within both the
4493 * node sets passed as arguments
4494 */
4495xmlNodeSetPtr
4496xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4497 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4498 int i, l1;
4499 xmlNodePtr cur;
4500
Daniel Veillardf88d8492008-04-01 08:00:31 +00004501 if (ret == NULL)
4502 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004503 if (xmlXPathNodeSetIsEmpty(nodes1))
4504 return(ret);
4505 if (xmlXPathNodeSetIsEmpty(nodes2))
4506 return(ret);
4507
4508 l1 = xmlXPathNodeSetGetLength(nodes1);
4509
4510 for (i = 0; i < l1; i++) {
4511 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004512 if (xmlXPathNodeSetContains(nodes2, cur)) {
4513 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4514 break;
4515 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004516 }
4517 return(ret);
4518}
4519
4520/**
4521 * xmlXPathDistinctSorted:
4522 * @nodes: a node-set, sorted by document order
4523 *
4524 * Implements the EXSLT - Sets distinct() function:
4525 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004526 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004527 * Returns a subset of the nodes contained in @nodes, or @nodes if
4528 * it is empty
4529 */
4530xmlNodeSetPtr
4531xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4532 xmlNodeSetPtr ret;
4533 xmlHashTablePtr hash;
4534 int i, l;
4535 xmlChar * strval;
4536 xmlNodePtr cur;
4537
4538 if (xmlXPathNodeSetIsEmpty(nodes))
4539 return(nodes);
4540
4541 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004542 if (ret == NULL)
4543 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004544 l = xmlXPathNodeSetGetLength(nodes);
4545 hash = xmlHashCreate (l);
4546 for (i = 0; i < l; i++) {
4547 cur = xmlXPathNodeSetItem(nodes, i);
4548 strval = xmlXPathCastNodeToString(cur);
4549 if (xmlHashLookup(hash, strval) == NULL) {
4550 xmlHashAddEntry(hash, strval, strval);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004551 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4552 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004553 } else {
4554 xmlFree(strval);
4555 }
4556 }
4557 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4558 return(ret);
4559}
4560
4561/**
4562 * xmlXPathDistinct:
4563 * @nodes: a node-set
4564 *
4565 * Implements the EXSLT - Sets distinct() function:
4566 * node-set set:distinct (node-set)
4567 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4568 * is called with the sorted node-set
4569 *
4570 * Returns a subset of the nodes contained in @nodes, or @nodes if
4571 * it is empty
4572 */
4573xmlNodeSetPtr
4574xmlXPathDistinct (xmlNodeSetPtr nodes) {
4575 if (xmlXPathNodeSetIsEmpty(nodes))
4576 return(nodes);
4577
4578 xmlXPathNodeSetSort(nodes);
4579 return(xmlXPathDistinctSorted(nodes));
4580}
4581
4582/**
4583 * xmlXPathHasSameNodes:
4584 * @nodes1: a node-set
4585 * @nodes2: a node-set
4586 *
4587 * Implements the EXSLT - Sets has-same-nodes function:
4588 * boolean set:has-same-node(node-set, node-set)
4589 *
4590 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4591 * otherwise
4592 */
4593int
4594xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4595 int i, l;
4596 xmlNodePtr cur;
4597
4598 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4599 xmlXPathNodeSetIsEmpty(nodes2))
4600 return(0);
4601
4602 l = xmlXPathNodeSetGetLength(nodes1);
4603 for (i = 0; i < l; i++) {
4604 cur = xmlXPathNodeSetItem(nodes1, i);
4605 if (xmlXPathNodeSetContains(nodes2, cur))
4606 return(1);
4607 }
4608 return(0);
4609}
4610
4611/**
4612 * xmlXPathNodeLeadingSorted:
4613 * @nodes: a node-set, sorted by document order
4614 * @node: a node
4615 *
4616 * Implements the EXSLT - Sets leading() function:
4617 * node-set set:leading (node-set, node-set)
4618 *
4619 * Returns the nodes in @nodes that precede @node in document order,
4620 * @nodes if @node is NULL or an empty node-set if @nodes
4621 * doesn't contain @node
4622 */
4623xmlNodeSetPtr
4624xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4625 int i, l;
4626 xmlNodePtr cur;
4627 xmlNodeSetPtr ret;
4628
4629 if (node == NULL)
4630 return(nodes);
4631
4632 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004633 if (ret == NULL)
4634 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004635 if (xmlXPathNodeSetIsEmpty(nodes) ||
4636 (!xmlXPathNodeSetContains(nodes, node)))
4637 return(ret);
4638
4639 l = xmlXPathNodeSetGetLength(nodes);
4640 for (i = 0; i < l; i++) {
4641 cur = xmlXPathNodeSetItem(nodes, i);
4642 if (cur == node)
4643 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004644 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4645 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004646 }
4647 return(ret);
4648}
4649
4650/**
4651 * xmlXPathNodeLeading:
4652 * @nodes: a node-set
4653 * @node: a node
4654 *
4655 * Implements the EXSLT - Sets leading() function:
4656 * node-set set:leading (node-set, node-set)
4657 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4658 * is called.
4659 *
4660 * Returns the nodes in @nodes that precede @node in document order,
4661 * @nodes if @node is NULL or an empty node-set if @nodes
4662 * doesn't contain @node
4663 */
4664xmlNodeSetPtr
4665xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4666 xmlXPathNodeSetSort(nodes);
4667 return(xmlXPathNodeLeadingSorted(nodes, node));
4668}
4669
4670/**
4671 * xmlXPathLeadingSorted:
4672 * @nodes1: a node-set, sorted by document order
4673 * @nodes2: a node-set, sorted by document order
4674 *
4675 * Implements the EXSLT - Sets leading() function:
4676 * node-set set:leading (node-set, node-set)
4677 *
4678 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4679 * in document order, @nodes1 if @nodes2 is NULL or empty or
4680 * an empty node-set if @nodes1 doesn't contain @nodes2
4681 */
4682xmlNodeSetPtr
4683xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4684 if (xmlXPathNodeSetIsEmpty(nodes2))
4685 return(nodes1);
4686 return(xmlXPathNodeLeadingSorted(nodes1,
4687 xmlXPathNodeSetItem(nodes2, 1)));
4688}
4689
4690/**
4691 * xmlXPathLeading:
4692 * @nodes1: a node-set
4693 * @nodes2: a node-set
4694 *
4695 * Implements the EXSLT - Sets leading() function:
4696 * node-set set:leading (node-set, node-set)
4697 * @nodes1 and @nodes2 are sorted by document order, then
4698 * #exslSetsLeadingSorted is called.
4699 *
4700 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4701 * in document order, @nodes1 if @nodes2 is NULL or empty or
4702 * an empty node-set if @nodes1 doesn't contain @nodes2
4703 */
4704xmlNodeSetPtr
4705xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4706 if (xmlXPathNodeSetIsEmpty(nodes2))
4707 return(nodes1);
4708 if (xmlXPathNodeSetIsEmpty(nodes1))
4709 return(xmlXPathNodeSetCreate(NULL));
4710 xmlXPathNodeSetSort(nodes1);
4711 xmlXPathNodeSetSort(nodes2);
4712 return(xmlXPathNodeLeadingSorted(nodes1,
4713 xmlXPathNodeSetItem(nodes2, 1)));
4714}
4715
4716/**
4717 * xmlXPathNodeTrailingSorted:
4718 * @nodes: a node-set, sorted by document order
4719 * @node: a node
4720 *
4721 * Implements the EXSLT - Sets trailing() function:
4722 * node-set set:trailing (node-set, node-set)
4723 *
4724 * Returns the nodes in @nodes that follow @node in document order,
4725 * @nodes if @node is NULL or an empty node-set if @nodes
4726 * doesn't contain @node
4727 */
4728xmlNodeSetPtr
4729xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4730 int i, l;
4731 xmlNodePtr cur;
4732 xmlNodeSetPtr ret;
4733
4734 if (node == NULL)
4735 return(nodes);
4736
4737 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004738 if (ret == NULL)
4739 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004740 if (xmlXPathNodeSetIsEmpty(nodes) ||
4741 (!xmlXPathNodeSetContains(nodes, node)))
4742 return(ret);
4743
4744 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004745 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004746 cur = xmlXPathNodeSetItem(nodes, i);
4747 if (cur == node)
4748 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004749 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4750 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004751 }
William M. Brack97ac8192007-06-06 17:19:24 +00004752 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004753 return(ret);
4754}
4755
4756/**
4757 * xmlXPathNodeTrailing:
4758 * @nodes: a node-set
4759 * @node: a node
4760 *
4761 * Implements the EXSLT - Sets trailing() function:
4762 * node-set set:trailing (node-set, node-set)
4763 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4764 * is called.
4765 *
4766 * Returns the nodes in @nodes that follow @node in document order,
4767 * @nodes if @node is NULL or an empty node-set if @nodes
4768 * doesn't contain @node
4769 */
4770xmlNodeSetPtr
4771xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4772 xmlXPathNodeSetSort(nodes);
4773 return(xmlXPathNodeTrailingSorted(nodes, node));
4774}
4775
4776/**
4777 * xmlXPathTrailingSorted:
4778 * @nodes1: a node-set, sorted by document order
4779 * @nodes2: a node-set, sorted by document order
4780 *
4781 * Implements the EXSLT - Sets trailing() function:
4782 * node-set set:trailing (node-set, node-set)
4783 *
4784 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4785 * in document order, @nodes1 if @nodes2 is NULL or empty or
4786 * an empty node-set if @nodes1 doesn't contain @nodes2
4787 */
4788xmlNodeSetPtr
4789xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4790 if (xmlXPathNodeSetIsEmpty(nodes2))
4791 return(nodes1);
4792 return(xmlXPathNodeTrailingSorted(nodes1,
4793 xmlXPathNodeSetItem(nodes2, 0)));
4794}
4795
4796/**
4797 * xmlXPathTrailing:
4798 * @nodes1: a node-set
4799 * @nodes2: a node-set
4800 *
4801 * Implements the EXSLT - Sets trailing() function:
4802 * node-set set:trailing (node-set, node-set)
4803 * @nodes1 and @nodes2 are sorted by document order, then
4804 * #xmlXPathTrailingSorted is called.
4805 *
4806 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4807 * in document order, @nodes1 if @nodes2 is NULL or empty or
4808 * an empty node-set if @nodes1 doesn't contain @nodes2
4809 */
4810xmlNodeSetPtr
4811xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4812 if (xmlXPathNodeSetIsEmpty(nodes2))
4813 return(nodes1);
4814 if (xmlXPathNodeSetIsEmpty(nodes1))
4815 return(xmlXPathNodeSetCreate(NULL));
4816 xmlXPathNodeSetSort(nodes1);
4817 xmlXPathNodeSetSort(nodes2);
4818 return(xmlXPathNodeTrailingSorted(nodes1,
4819 xmlXPathNodeSetItem(nodes2, 0)));
4820}
4821
Owen Taylor3473f882001-02-23 17:55:21 +00004822/************************************************************************
4823 * *
4824 * Routines to handle extra functions *
4825 * *
4826 ************************************************************************/
4827
4828/**
4829 * xmlXPathRegisterFunc:
4830 * @ctxt: the XPath context
4831 * @name: the function name
4832 * @f: the function implementation or NULL
4833 *
4834 * Register a new function. If @f is NULL it unregisters the function
4835 *
4836 * Returns 0 in case of success, -1 in case of error
4837 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004838int
Owen Taylor3473f882001-02-23 17:55:21 +00004839xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4840 xmlXPathFunction f) {
4841 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4842}
4843
4844/**
4845 * xmlXPathRegisterFuncNS:
4846 * @ctxt: the XPath context
4847 * @name: the function name
4848 * @ns_uri: the function namespace URI
4849 * @f: the function implementation or NULL
4850 *
4851 * Register a new function. If @f is NULL it unregisters the function
4852 *
4853 * Returns 0 in case of success, -1 in case of error
4854 */
4855int
4856xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4857 const xmlChar *ns_uri, xmlXPathFunction f) {
4858 if (ctxt == NULL)
4859 return(-1);
4860 if (name == NULL)
4861 return(-1);
4862
4863 if (ctxt->funcHash == NULL)
4864 ctxt->funcHash = xmlHashCreate(0);
4865 if (ctxt->funcHash == NULL)
4866 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004867 if (f == NULL)
4868 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004869 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004870}
4871
4872/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004873 * xmlXPathRegisterFuncLookup:
4874 * @ctxt: the XPath context
4875 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004876 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004877 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004878 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004879 */
4880void
4881xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4882 xmlXPathFuncLookupFunc f,
4883 void *funcCtxt) {
4884 if (ctxt == NULL)
4885 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004886 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004887 ctxt->funcLookupData = funcCtxt;
4888}
4889
4890/**
Owen Taylor3473f882001-02-23 17:55:21 +00004891 * xmlXPathFunctionLookup:
4892 * @ctxt: the XPath context
4893 * @name: the function name
4894 *
4895 * Search in the Function array of the context for the given
4896 * function.
4897 *
4898 * Returns the xmlXPathFunction or NULL if not found
4899 */
4900xmlXPathFunction
4901xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004902 if (ctxt == NULL)
4903 return (NULL);
4904
4905 if (ctxt->funcLookupFunc != NULL) {
4906 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004907 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004908
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004909 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004910 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004911 if (ret != NULL)
4912 return(ret);
4913 }
Owen Taylor3473f882001-02-23 17:55:21 +00004914 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4915}
4916
4917/**
4918 * xmlXPathFunctionLookupNS:
4919 * @ctxt: the XPath context
4920 * @name: the function name
4921 * @ns_uri: the function namespace URI
4922 *
4923 * Search in the Function array of the context for the given
4924 * function.
4925 *
4926 * Returns the xmlXPathFunction or NULL if not found
4927 */
4928xmlXPathFunction
4929xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4930 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004931 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004932
Owen Taylor3473f882001-02-23 17:55:21 +00004933 if (ctxt == NULL)
4934 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004935 if (name == NULL)
4936 return(NULL);
4937
Thomas Broyerba4ad322001-07-26 16:55:21 +00004938 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004939 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004940
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004941 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004942 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004943 if (ret != NULL)
4944 return(ret);
4945 }
4946
4947 if (ctxt->funcHash == NULL)
4948 return(NULL);
4949
William M. Brackad0e67c2004-12-01 14:35:10 +00004950 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4951 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004952}
4953
4954/**
4955 * xmlXPathRegisteredFuncsCleanup:
4956 * @ctxt: the XPath context
4957 *
4958 * Cleanup the XPath context data associated to registered functions
4959 */
4960void
4961xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4962 if (ctxt == NULL)
4963 return;
4964
4965 xmlHashFree(ctxt->funcHash, NULL);
4966 ctxt->funcHash = NULL;
4967}
4968
4969/************************************************************************
4970 * *
William M. Brack08171912003-12-29 02:52:11 +00004971 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004972 * *
4973 ************************************************************************/
4974
4975/**
4976 * xmlXPathRegisterVariable:
4977 * @ctxt: the XPath context
4978 * @name: the variable name
4979 * @value: the variable value or NULL
4980 *
4981 * Register a new variable value. If @value is NULL it unregisters
4982 * the variable
4983 *
4984 * Returns 0 in case of success, -1 in case of error
4985 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004986int
Owen Taylor3473f882001-02-23 17:55:21 +00004987xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4988 xmlXPathObjectPtr value) {
4989 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4990}
4991
4992/**
4993 * xmlXPathRegisterVariableNS:
4994 * @ctxt: the XPath context
4995 * @name: the variable name
4996 * @ns_uri: the variable namespace URI
4997 * @value: the variable value or NULL
4998 *
4999 * Register a new variable value. If @value is NULL it unregisters
5000 * the variable
5001 *
5002 * Returns 0 in case of success, -1 in case of error
5003 */
5004int
5005xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5006 const xmlChar *ns_uri,
5007 xmlXPathObjectPtr value) {
5008 if (ctxt == NULL)
5009 return(-1);
5010 if (name == NULL)
5011 return(-1);
5012
5013 if (ctxt->varHash == NULL)
5014 ctxt->varHash = xmlHashCreate(0);
5015 if (ctxt->varHash == NULL)
5016 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00005017 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005018 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00005019 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00005020 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5021 (void *) value,
5022 (xmlHashDeallocator)xmlXPathFreeObject));
5023}
5024
5025/**
5026 * xmlXPathRegisterVariableLookup:
5027 * @ctxt: the XPath context
5028 * @f: the lookup function
5029 * @data: the lookup data
5030 *
5031 * register an external mechanism to do variable lookup
5032 */
5033void
5034xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5035 xmlXPathVariableLookupFunc f, void *data) {
5036 if (ctxt == NULL)
5037 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00005038 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00005039 ctxt->varLookupData = data;
5040}
5041
5042/**
5043 * xmlXPathVariableLookup:
5044 * @ctxt: the XPath context
5045 * @name: the variable name
5046 *
5047 * Search in the Variable array of the context for the given
5048 * variable value.
5049 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005050 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005051 */
5052xmlXPathObjectPtr
5053xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5054 if (ctxt == NULL)
5055 return(NULL);
5056
5057 if (ctxt->varLookupFunc != NULL) {
5058 xmlXPathObjectPtr ret;
5059
5060 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5061 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00005062 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005063 }
5064 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5065}
5066
5067/**
5068 * xmlXPathVariableLookupNS:
5069 * @ctxt: the XPath context
5070 * @name: the variable name
5071 * @ns_uri: the variable namespace URI
5072 *
5073 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005074 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005075 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005076 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005077 */
5078xmlXPathObjectPtr
5079xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5080 const xmlChar *ns_uri) {
5081 if (ctxt == NULL)
5082 return(NULL);
5083
5084 if (ctxt->varLookupFunc != NULL) {
5085 xmlXPathObjectPtr ret;
5086
5087 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5088 (ctxt->varLookupData, name, ns_uri);
5089 if (ret != NULL) return(ret);
5090 }
5091
5092 if (ctxt->varHash == NULL)
5093 return(NULL);
5094 if (name == NULL)
5095 return(NULL);
5096
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005097 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005098 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005099}
5100
5101/**
5102 * xmlXPathRegisteredVariablesCleanup:
5103 * @ctxt: the XPath context
5104 *
5105 * Cleanup the XPath context data associated to registered variables
5106 */
5107void
5108xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5109 if (ctxt == NULL)
5110 return;
5111
Daniel Veillard76d66f42001-05-16 21:05:17 +00005112 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005113 ctxt->varHash = NULL;
5114}
5115
5116/**
5117 * xmlXPathRegisterNs:
5118 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005119 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005120 * @ns_uri: the namespace name
5121 *
5122 * Register a new namespace. If @ns_uri is NULL it unregisters
5123 * the namespace
5124 *
5125 * Returns 0 in case of success, -1 in case of error
5126 */
5127int
5128xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5129 const xmlChar *ns_uri) {
5130 if (ctxt == NULL)
5131 return(-1);
5132 if (prefix == NULL)
5133 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005134 if (prefix[0] == 0)
5135 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005136
5137 if (ctxt->nsHash == NULL)
5138 ctxt->nsHash = xmlHashCreate(10);
5139 if (ctxt->nsHash == NULL)
5140 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005141 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005142 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005143 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005144 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005145 (xmlHashDeallocator)xmlFree));
5146}
5147
5148/**
5149 * xmlXPathNsLookup:
5150 * @ctxt: the XPath context
5151 * @prefix: the namespace prefix value
5152 *
5153 * Search in the namespace declaration array of the context for the given
5154 * namespace name associated to the given prefix
5155 *
5156 * Returns the value or NULL if not found
5157 */
5158const xmlChar *
5159xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5160 if (ctxt == NULL)
5161 return(NULL);
5162 if (prefix == NULL)
5163 return(NULL);
5164
5165#ifdef XML_XML_NAMESPACE
5166 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5167 return(XML_XML_NAMESPACE);
5168#endif
5169
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005170 if (ctxt->namespaces != NULL) {
5171 int i;
5172
5173 for (i = 0;i < ctxt->nsNr;i++) {
5174 if ((ctxt->namespaces[i] != NULL) &&
5175 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5176 return(ctxt->namespaces[i]->href);
5177 }
5178 }
Owen Taylor3473f882001-02-23 17:55:21 +00005179
5180 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5181}
5182
5183/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005184 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005185 * @ctxt: the XPath context
5186 *
5187 * Cleanup the XPath context data associated to registered variables
5188 */
5189void
5190xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5191 if (ctxt == NULL)
5192 return;
5193
Daniel Veillard42766c02002-08-22 20:52:17 +00005194 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005195 ctxt->nsHash = NULL;
5196}
5197
5198/************************************************************************
5199 * *
5200 * Routines to handle Values *
5201 * *
5202 ************************************************************************/
5203
William M. Brack08171912003-12-29 02:52:11 +00005204/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005205
5206/**
5207 * xmlXPathNewFloat:
5208 * @val: the double value
5209 *
5210 * Create a new xmlXPathObjectPtr of type double and of value @val
5211 *
5212 * Returns the newly created object.
5213 */
5214xmlXPathObjectPtr
5215xmlXPathNewFloat(double val) {
5216 xmlXPathObjectPtr ret;
5217
5218 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5219 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005220 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005221 return(NULL);
5222 }
5223 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5224 ret->type = XPATH_NUMBER;
5225 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005226#ifdef XP_DEBUG_OBJ_USAGE
5227 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5228#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005229 return(ret);
5230}
5231
5232/**
5233 * xmlXPathNewBoolean:
5234 * @val: the boolean value
5235 *
5236 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5237 *
5238 * Returns the newly created object.
5239 */
5240xmlXPathObjectPtr
5241xmlXPathNewBoolean(int val) {
5242 xmlXPathObjectPtr ret;
5243
5244 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5245 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005246 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005247 return(NULL);
5248 }
5249 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5250 ret->type = XPATH_BOOLEAN;
5251 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005252#ifdef XP_DEBUG_OBJ_USAGE
5253 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5254#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005255 return(ret);
5256}
5257
5258/**
5259 * xmlXPathNewString:
5260 * @val: the xmlChar * value
5261 *
5262 * Create a new xmlXPathObjectPtr of type string and of value @val
5263 *
5264 * Returns the newly created object.
5265 */
5266xmlXPathObjectPtr
5267xmlXPathNewString(const xmlChar *val) {
5268 xmlXPathObjectPtr ret;
5269
5270 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5271 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005272 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005273 return(NULL);
5274 }
5275 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5276 ret->type = XPATH_STRING;
5277 if (val != NULL)
5278 ret->stringval = xmlStrdup(val);
5279 else
5280 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005281#ifdef XP_DEBUG_OBJ_USAGE
5282 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5283#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005284 return(ret);
5285}
5286
5287/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005288 * xmlXPathWrapString:
5289 * @val: the xmlChar * value
5290 *
5291 * Wraps the @val string into an XPath object.
5292 *
5293 * Returns the newly created object.
5294 */
5295xmlXPathObjectPtr
5296xmlXPathWrapString (xmlChar *val) {
5297 xmlXPathObjectPtr ret;
5298
5299 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5300 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005301 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005302 return(NULL);
5303 }
5304 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5305 ret->type = XPATH_STRING;
5306 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005307#ifdef XP_DEBUG_OBJ_USAGE
5308 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5309#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005310 return(ret);
5311}
5312
5313/**
Owen Taylor3473f882001-02-23 17:55:21 +00005314 * xmlXPathNewCString:
5315 * @val: the char * value
5316 *
5317 * Create a new xmlXPathObjectPtr of type string and of value @val
5318 *
5319 * Returns the newly created object.
5320 */
5321xmlXPathObjectPtr
5322xmlXPathNewCString(const char *val) {
5323 xmlXPathObjectPtr ret;
5324
5325 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5326 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005327 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005328 return(NULL);
5329 }
5330 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5331 ret->type = XPATH_STRING;
5332 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005333#ifdef XP_DEBUG_OBJ_USAGE
5334 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5335#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005336 return(ret);
5337}
5338
5339/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005340 * xmlXPathWrapCString:
5341 * @val: the char * value
5342 *
5343 * Wraps a string into an XPath object.
5344 *
5345 * Returns the newly created object.
5346 */
5347xmlXPathObjectPtr
5348xmlXPathWrapCString (char * val) {
5349 return(xmlXPathWrapString((xmlChar *)(val)));
5350}
5351
5352/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005353 * xmlXPathWrapExternal:
5354 * @val: the user data
5355 *
5356 * Wraps the @val data into an XPath object.
5357 *
5358 * Returns the newly created object.
5359 */
5360xmlXPathObjectPtr
5361xmlXPathWrapExternal (void *val) {
5362 xmlXPathObjectPtr ret;
5363
5364 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5365 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005366 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005367 return(NULL);
5368 }
5369 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5370 ret->type = XPATH_USERS;
5371 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005372#ifdef XP_DEBUG_OBJ_USAGE
5373 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5374#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005375 return(ret);
5376}
5377
5378/**
Owen Taylor3473f882001-02-23 17:55:21 +00005379 * xmlXPathObjectCopy:
5380 * @val: the original object
5381 *
5382 * allocate a new copy of a given object
5383 *
5384 * Returns the newly created object.
5385 */
5386xmlXPathObjectPtr
5387xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5388 xmlXPathObjectPtr ret;
5389
5390 if (val == NULL)
5391 return(NULL);
5392
5393 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5394 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005395 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005396 return(NULL);
5397 }
5398 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005399#ifdef XP_DEBUG_OBJ_USAGE
5400 xmlXPathDebugObjUsageRequested(NULL, val->type);
5401#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005402 switch (val->type) {
5403 case XPATH_BOOLEAN:
5404 case XPATH_NUMBER:
5405 case XPATH_POINT:
5406 case XPATH_RANGE:
5407 break;
5408 case XPATH_STRING:
5409 ret->stringval = xmlStrdup(val->stringval);
5410 break;
5411 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005412#if 0
5413/*
5414 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5415 this previous handling is no longer correct, and can cause some serious
5416 problems (ref. bug 145547)
5417*/
Owen Taylor3473f882001-02-23 17:55:21 +00005418 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005419 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005420 xmlNodePtr cur, tmp;
5421 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005422
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005423 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005424 top = xmlNewDoc(NULL);
5425 top->name = (char *)
5426 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005427 ret->user = top;
5428 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005429 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005430 cur = val->nodesetval->nodeTab[0]->children;
5431 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005432 tmp = xmlDocCopyNode(cur, top, 1);
5433 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005434 cur = cur->next;
5435 }
5436 }
William M. Bracke9449c52004-07-11 14:41:20 +00005437
Daniel Veillard9adc0462003-03-24 18:39:54 +00005438 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005439 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005440 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005441 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005442 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005443#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005444 case XPATH_NODESET:
5445 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005446 /* Do not deallocate the copied tree value */
5447 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005448 break;
5449 case XPATH_LOCATIONSET:
5450#ifdef LIBXML_XPTR_ENABLED
5451 {
5452 xmlLocationSetPtr loc = val->user;
5453 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5454 break;
5455 }
5456#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005457 case XPATH_USERS:
5458 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005459 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005460 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005461 xmlGenericError(xmlGenericErrorContext,
5462 "xmlXPathObjectCopy: unsupported type %d\n",
5463 val->type);
5464 break;
5465 }
5466 return(ret);
5467}
5468
5469/**
5470 * xmlXPathFreeObject:
5471 * @obj: the object to free
5472 *
5473 * Free up an xmlXPathObjectPtr object.
5474 */
5475void
5476xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5477 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005478 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005479 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005480#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005481 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005482 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005483 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005484 } else
5485#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005486 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005487 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005488 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005489 } else {
5490 if (obj->nodesetval != NULL)
5491 xmlXPathFreeNodeSet(obj->nodesetval);
5492 }
Owen Taylor3473f882001-02-23 17:55:21 +00005493#ifdef LIBXML_XPTR_ENABLED
5494 } else if (obj->type == XPATH_LOCATIONSET) {
5495 if (obj->user != NULL)
5496 xmlXPtrFreeLocationSet(obj->user);
5497#endif
5498 } else if (obj->type == XPATH_STRING) {
5499 if (obj->stringval != NULL)
5500 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005501 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005502#ifdef XP_DEBUG_OBJ_USAGE
5503 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5504#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005505 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005506}
Owen Taylor3473f882001-02-23 17:55:21 +00005507
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005508/**
5509 * xmlXPathReleaseObject:
5510 * @obj: the xmlXPathObjectPtr to free or to cache
5511 *
5512 * Depending on the state of the cache this frees the given
5513 * XPath object or stores it in the cache.
5514 */
5515static void
5516xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5517{
5518#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5519 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5520 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5521
5522#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5523
5524 if (obj == NULL)
5525 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005526 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005527 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005528 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005529 xmlXPathContextCachePtr cache =
5530 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005531
5532 switch (obj->type) {
5533 case XPATH_NODESET:
5534 case XPATH_XSLT_TREE:
5535 if (obj->nodesetval != NULL) {
5536 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005537 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005538 * It looks like the @boolval is used for
5539 * evaluation if this an XSLT Result Tree Fragment.
5540 * TODO: Check if this assumption is correct.
5541 */
5542 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5543 xmlXPathFreeValueTree(obj->nodesetval);
5544 obj->nodesetval = NULL;
5545 } else if ((obj->nodesetval->nodeMax <= 40) &&
5546 (XP_CACHE_WANTS(cache->nodesetObjs,
5547 cache->maxNodeset)))
5548 {
5549 XP_CACHE_ADD(cache->nodesetObjs, obj);
5550 goto obj_cached;
5551 } else {
5552 xmlXPathFreeNodeSet(obj->nodesetval);
5553 obj->nodesetval = NULL;
5554 }
5555 }
5556 break;
5557 case XPATH_STRING:
5558 if (obj->stringval != NULL)
5559 xmlFree(obj->stringval);
5560
5561 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5562 XP_CACHE_ADD(cache->stringObjs, obj);
5563 goto obj_cached;
5564 }
5565 break;
5566 case XPATH_BOOLEAN:
5567 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5568 XP_CACHE_ADD(cache->booleanObjs, obj);
5569 goto obj_cached;
5570 }
5571 break;
5572 case XPATH_NUMBER:
5573 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5574 XP_CACHE_ADD(cache->numberObjs, obj);
5575 goto obj_cached;
5576 }
5577 break;
5578#ifdef LIBXML_XPTR_ENABLED
5579 case XPATH_LOCATIONSET:
5580 if (obj->user != NULL) {
5581 xmlXPtrFreeLocationSet(obj->user);
5582 }
5583 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005584#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005585 default:
5586 goto free_obj;
5587 }
5588
5589 /*
5590 * Fallback to adding to the misc-objects slot.
5591 */
5592 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5593 XP_CACHE_ADD(cache->miscObjs, obj);
5594 } else
5595 goto free_obj;
5596
5597obj_cached:
5598
5599#ifdef XP_DEBUG_OBJ_USAGE
5600 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5601#endif
5602
5603 if (obj->nodesetval != NULL) {
5604 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005605
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005606 /*
5607 * TODO: Due to those nasty ns-nodes, we need to traverse
5608 * the list and free the ns-nodes.
5609 * URGENT TODO: Check if it's actually slowing things down.
5610 * Maybe we shouldn't try to preserve the list.
5611 */
5612 if (tmpset->nodeNr > 1) {
5613 int i;
5614 xmlNodePtr node;
5615
5616 for (i = 0; i < tmpset->nodeNr; i++) {
5617 node = tmpset->nodeTab[i];
5618 if ((node != NULL) &&
5619 (node->type == XML_NAMESPACE_DECL))
5620 {
5621 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5622 }
5623 }
5624 } else if (tmpset->nodeNr == 1) {
5625 if ((tmpset->nodeTab[0] != NULL) &&
5626 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5627 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005628 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005629 tmpset->nodeNr = 0;
5630 memset(obj, 0, sizeof(xmlXPathObject));
5631 obj->nodesetval = tmpset;
5632 } else
5633 memset(obj, 0, sizeof(xmlXPathObject));
5634
5635 return;
5636
5637free_obj:
5638 /*
5639 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005640 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005641 if (obj->nodesetval != NULL)
5642 xmlXPathFreeNodeSet(obj->nodesetval);
5643#ifdef XP_DEBUG_OBJ_USAGE
5644 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5645#endif
5646 xmlFree(obj);
5647 }
5648 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005649}
5650
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005651
5652/************************************************************************
5653 * *
5654 * Type Casting Routines *
5655 * *
5656 ************************************************************************/
5657
5658/**
5659 * xmlXPathCastBooleanToString:
5660 * @val: a boolean
5661 *
5662 * Converts a boolean to its string value.
5663 *
5664 * Returns a newly allocated string.
5665 */
5666xmlChar *
5667xmlXPathCastBooleanToString (int val) {
5668 xmlChar *ret;
5669 if (val)
5670 ret = xmlStrdup((const xmlChar *) "true");
5671 else
5672 ret = xmlStrdup((const xmlChar *) "false");
5673 return(ret);
5674}
5675
5676/**
5677 * xmlXPathCastNumberToString:
5678 * @val: a number
5679 *
5680 * Converts a number to its string value.
5681 *
5682 * Returns a newly allocated string.
5683 */
5684xmlChar *
5685xmlXPathCastNumberToString (double val) {
5686 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005687 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005688 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005689 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005690 break;
5691 case -1:
5692 ret = xmlStrdup((const xmlChar *) "-Infinity");
5693 break;
5694 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005695 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005696 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005697 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5698 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005699 } else {
5700 /* could be improved */
5701 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005702 xmlXPathFormatNumber(val, buf, 99);
5703 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005704 ret = xmlStrdup((const xmlChar *) buf);
5705 }
5706 }
5707 return(ret);
5708}
5709
5710/**
5711 * xmlXPathCastNodeToString:
5712 * @node: a node
5713 *
5714 * Converts a node to its string value.
5715 *
5716 * Returns a newly allocated string.
5717 */
5718xmlChar *
5719xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005720xmlChar *ret;
5721 if ((ret = xmlNodeGetContent(node)) == NULL)
5722 ret = xmlStrdup((const xmlChar *) "");
5723 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005724}
5725
5726/**
5727 * xmlXPathCastNodeSetToString:
5728 * @ns: a node-set
5729 *
5730 * Converts a node-set to its string value.
5731 *
5732 * Returns a newly allocated string.
5733 */
5734xmlChar *
5735xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5736 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5737 return(xmlStrdup((const xmlChar *) ""));
5738
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005739 if (ns->nodeNr > 1)
5740 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005741 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5742}
5743
5744/**
5745 * xmlXPathCastToString:
5746 * @val: an XPath object
5747 *
5748 * Converts an existing object to its string() equivalent
5749 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005750 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005751 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005752 */
5753xmlChar *
5754xmlXPathCastToString(xmlXPathObjectPtr val) {
5755 xmlChar *ret = NULL;
5756
5757 if (val == NULL)
5758 return(xmlStrdup((const xmlChar *) ""));
5759 switch (val->type) {
5760 case XPATH_UNDEFINED:
5761#ifdef DEBUG_EXPR
5762 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5763#endif
5764 ret = xmlStrdup((const xmlChar *) "");
5765 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005766 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005767 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005768 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5769 break;
5770 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005771 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005772 case XPATH_BOOLEAN:
5773 ret = xmlXPathCastBooleanToString(val->boolval);
5774 break;
5775 case XPATH_NUMBER: {
5776 ret = xmlXPathCastNumberToString(val->floatval);
5777 break;
5778 }
5779 case XPATH_USERS:
5780 case XPATH_POINT:
5781 case XPATH_RANGE:
5782 case XPATH_LOCATIONSET:
5783 TODO
5784 ret = xmlStrdup((const xmlChar *) "");
5785 break;
5786 }
5787 return(ret);
5788}
5789
5790/**
5791 * xmlXPathConvertString:
5792 * @val: an XPath object
5793 *
5794 * Converts an existing object to its string() equivalent
5795 *
5796 * Returns the new object, the old one is freed (or the operation
5797 * is done directly on @val)
5798 */
5799xmlXPathObjectPtr
5800xmlXPathConvertString(xmlXPathObjectPtr val) {
5801 xmlChar *res = NULL;
5802
5803 if (val == NULL)
5804 return(xmlXPathNewCString(""));
5805
5806 switch (val->type) {
5807 case XPATH_UNDEFINED:
5808#ifdef DEBUG_EXPR
5809 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5810#endif
5811 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005812 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005813 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005814 res = xmlXPathCastNodeSetToString(val->nodesetval);
5815 break;
5816 case XPATH_STRING:
5817 return(val);
5818 case XPATH_BOOLEAN:
5819 res = xmlXPathCastBooleanToString(val->boolval);
5820 break;
5821 case XPATH_NUMBER:
5822 res = xmlXPathCastNumberToString(val->floatval);
5823 break;
5824 case XPATH_USERS:
5825 case XPATH_POINT:
5826 case XPATH_RANGE:
5827 case XPATH_LOCATIONSET:
5828 TODO;
5829 break;
5830 }
5831 xmlXPathFreeObject(val);
5832 if (res == NULL)
5833 return(xmlXPathNewCString(""));
5834 return(xmlXPathWrapString(res));
5835}
5836
5837/**
5838 * xmlXPathCastBooleanToNumber:
5839 * @val: a boolean
5840 *
5841 * Converts a boolean to its number value
5842 *
5843 * Returns the number value
5844 */
5845double
5846xmlXPathCastBooleanToNumber(int val) {
5847 if (val)
5848 return(1.0);
5849 return(0.0);
5850}
5851
5852/**
5853 * xmlXPathCastStringToNumber:
5854 * @val: a string
5855 *
5856 * Converts a string to its number value
5857 *
5858 * Returns the number value
5859 */
5860double
5861xmlXPathCastStringToNumber(const xmlChar * val) {
5862 return(xmlXPathStringEvalNumber(val));
5863}
5864
5865/**
5866 * xmlXPathCastNodeToNumber:
5867 * @node: a node
5868 *
5869 * Converts a node to its number value
5870 *
5871 * Returns the number value
5872 */
5873double
5874xmlXPathCastNodeToNumber (xmlNodePtr node) {
5875 xmlChar *strval;
5876 double ret;
5877
5878 if (node == NULL)
5879 return(xmlXPathNAN);
5880 strval = xmlXPathCastNodeToString(node);
5881 if (strval == NULL)
5882 return(xmlXPathNAN);
5883 ret = xmlXPathCastStringToNumber(strval);
5884 xmlFree(strval);
5885
5886 return(ret);
5887}
5888
5889/**
5890 * xmlXPathCastNodeSetToNumber:
5891 * @ns: a node-set
5892 *
5893 * Converts a node-set to its number value
5894 *
5895 * Returns the number value
5896 */
5897double
5898xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5899 xmlChar *str;
5900 double ret;
5901
5902 if (ns == NULL)
5903 return(xmlXPathNAN);
5904 str = xmlXPathCastNodeSetToString(ns);
5905 ret = xmlXPathCastStringToNumber(str);
5906 xmlFree(str);
5907 return(ret);
5908}
5909
5910/**
5911 * xmlXPathCastToNumber:
5912 * @val: an XPath object
5913 *
5914 * Converts an XPath object to its number value
5915 *
5916 * Returns the number value
5917 */
5918double
5919xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5920 double ret = 0.0;
5921
5922 if (val == NULL)
5923 return(xmlXPathNAN);
5924 switch (val->type) {
5925 case XPATH_UNDEFINED:
5926#ifdef DEGUB_EXPR
5927 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5928#endif
5929 ret = xmlXPathNAN;
5930 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005931 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005932 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005933 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5934 break;
5935 case XPATH_STRING:
5936 ret = xmlXPathCastStringToNumber(val->stringval);
5937 break;
5938 case XPATH_NUMBER:
5939 ret = val->floatval;
5940 break;
5941 case XPATH_BOOLEAN:
5942 ret = xmlXPathCastBooleanToNumber(val->boolval);
5943 break;
5944 case XPATH_USERS:
5945 case XPATH_POINT:
5946 case XPATH_RANGE:
5947 case XPATH_LOCATIONSET:
5948 TODO;
5949 ret = xmlXPathNAN;
5950 break;
5951 }
5952 return(ret);
5953}
5954
5955/**
5956 * xmlXPathConvertNumber:
5957 * @val: an XPath object
5958 *
5959 * Converts an existing object to its number() equivalent
5960 *
5961 * Returns the new object, the old one is freed (or the operation
5962 * is done directly on @val)
5963 */
5964xmlXPathObjectPtr
5965xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5966 xmlXPathObjectPtr ret;
5967
5968 if (val == NULL)
5969 return(xmlXPathNewFloat(0.0));
5970 if (val->type == XPATH_NUMBER)
5971 return(val);
5972 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5973 xmlXPathFreeObject(val);
5974 return(ret);
5975}
5976
5977/**
5978 * xmlXPathCastNumberToBoolean:
5979 * @val: a number
5980 *
5981 * Converts a number to its boolean value
5982 *
5983 * Returns the boolean value
5984 */
5985int
5986xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005987 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005988 return(0);
5989 return(1);
5990}
5991
5992/**
5993 * xmlXPathCastStringToBoolean:
5994 * @val: a string
5995 *
5996 * Converts a string to its boolean value
5997 *
5998 * Returns the boolean value
5999 */
6000int
6001xmlXPathCastStringToBoolean (const xmlChar *val) {
6002 if ((val == NULL) || (xmlStrlen(val) == 0))
6003 return(0);
6004 return(1);
6005}
6006
6007/**
6008 * xmlXPathCastNodeSetToBoolean:
6009 * @ns: a node-set
6010 *
6011 * Converts a node-set to its boolean value
6012 *
6013 * Returns the boolean value
6014 */
6015int
6016xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6017 if ((ns == NULL) || (ns->nodeNr == 0))
6018 return(0);
6019 return(1);
6020}
6021
6022/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006023 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006024 * @val: an XPath object
6025 *
6026 * Converts an XPath object to its boolean value
6027 *
6028 * Returns the boolean value
6029 */
6030int
6031xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6032 int ret = 0;
6033
6034 if (val == NULL)
6035 return(0);
6036 switch (val->type) {
6037 case XPATH_UNDEFINED:
6038#ifdef DEBUG_EXPR
6039 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6040#endif
6041 ret = 0;
6042 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006043 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00006044 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006045 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6046 break;
6047 case XPATH_STRING:
6048 ret = xmlXPathCastStringToBoolean(val->stringval);
6049 break;
6050 case XPATH_NUMBER:
6051 ret = xmlXPathCastNumberToBoolean(val->floatval);
6052 break;
6053 case XPATH_BOOLEAN:
6054 ret = val->boolval;
6055 break;
6056 case XPATH_USERS:
6057 case XPATH_POINT:
6058 case XPATH_RANGE:
6059 case XPATH_LOCATIONSET:
6060 TODO;
6061 ret = 0;
6062 break;
6063 }
6064 return(ret);
6065}
6066
6067
6068/**
6069 * xmlXPathConvertBoolean:
6070 * @val: an XPath object
6071 *
6072 * Converts an existing object to its boolean() equivalent
6073 *
6074 * Returns the new object, the old one is freed (or the operation
6075 * is done directly on @val)
6076 */
6077xmlXPathObjectPtr
6078xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6079 xmlXPathObjectPtr ret;
6080
6081 if (val == NULL)
6082 return(xmlXPathNewBoolean(0));
6083 if (val->type == XPATH_BOOLEAN)
6084 return(val);
6085 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6086 xmlXPathFreeObject(val);
6087 return(ret);
6088}
6089
Owen Taylor3473f882001-02-23 17:55:21 +00006090/************************************************************************
6091 * *
6092 * Routines to handle XPath contexts *
6093 * *
6094 ************************************************************************/
6095
6096/**
6097 * xmlXPathNewContext:
6098 * @doc: the XML document
6099 *
6100 * Create a new xmlXPathContext
6101 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006102 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006103 */
6104xmlXPathContextPtr
6105xmlXPathNewContext(xmlDocPtr doc) {
6106 xmlXPathContextPtr ret;
6107
6108 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6109 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006110 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006111 return(NULL);
6112 }
6113 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6114 ret->doc = doc;
6115 ret->node = NULL;
6116
6117 ret->varHash = NULL;
6118
6119 ret->nb_types = 0;
6120 ret->max_types = 0;
6121 ret->types = NULL;
6122
6123 ret->funcHash = xmlHashCreate(0);
6124
6125 ret->nb_axis = 0;
6126 ret->max_axis = 0;
6127 ret->axis = NULL;
6128
6129 ret->nsHash = NULL;
6130 ret->user = NULL;
6131
6132 ret->contextSize = -1;
6133 ret->proximityPosition = -1;
6134
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006135#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006136 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006137 xmlXPathFreeContext(ret);
6138 return(NULL);
6139 }
6140#endif
6141
Daniel Veillard45490ae2008-07-29 09:13:19 +00006142 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006143
Owen Taylor3473f882001-02-23 17:55:21 +00006144 return(ret);
6145}
6146
6147/**
6148 * xmlXPathFreeContext:
6149 * @ctxt: the context to free
6150 *
6151 * Free up an xmlXPathContext
6152 */
6153void
6154xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006155 if (ctxt == NULL) return;
6156
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006157 if (ctxt->cache != NULL)
6158 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006159 xmlXPathRegisteredNsCleanup(ctxt);
6160 xmlXPathRegisteredFuncsCleanup(ctxt);
6161 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006162 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006163 xmlFree(ctxt);
6164}
6165
6166/************************************************************************
6167 * *
6168 * Routines to handle XPath parser contexts *
6169 * *
6170 ************************************************************************/
6171
6172#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006173 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006174 __xmlRaiseError(NULL, NULL, NULL, \
6175 NULL, NULL, XML_FROM_XPATH, \
6176 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6177 __FILE__, __LINE__, \
6178 NULL, NULL, NULL, 0, 0, \
6179 "NULL context pointer\n"); \
6180 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006181 } \
6182
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006183#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006184 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006185 __xmlRaiseError(NULL, NULL, NULL, \
6186 NULL, NULL, XML_FROM_XPATH, \
6187 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6188 __FILE__, __LINE__, \
6189 NULL, NULL, NULL, 0, 0, \
6190 "NULL context pointer\n"); \
6191 return(-1); \
6192 } \
6193
Owen Taylor3473f882001-02-23 17:55:21 +00006194
6195#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006196 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006197 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006198 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006199 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006200 }
Owen Taylor3473f882001-02-23 17:55:21 +00006201
6202
6203/**
6204 * xmlXPathNewParserContext:
6205 * @str: the XPath expression
6206 * @ctxt: the XPath context
6207 *
6208 * Create a new xmlXPathParserContext
6209 *
6210 * Returns the xmlXPathParserContext just allocated.
6211 */
6212xmlXPathParserContextPtr
6213xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6214 xmlXPathParserContextPtr ret;
6215
6216 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6217 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006218 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006219 return(NULL);
6220 }
6221 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6222 ret->cur = ret->base = str;
6223 ret->context = ctxt;
6224
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006225 ret->comp = xmlXPathNewCompExpr();
6226 if (ret->comp == NULL) {
6227 xmlFree(ret->valueTab);
6228 xmlFree(ret);
6229 return(NULL);
6230 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006231 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6232 ret->comp->dict = ctxt->dict;
6233 xmlDictReference(ret->comp->dict);
6234 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006235
6236 return(ret);
6237}
6238
6239/**
6240 * xmlXPathCompParserContext:
6241 * @comp: the XPath compiled expression
6242 * @ctxt: the XPath context
6243 *
6244 * Create a new xmlXPathParserContext when processing a compiled expression
6245 *
6246 * Returns the xmlXPathParserContext just allocated.
6247 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006248static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006249xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6250 xmlXPathParserContextPtr ret;
6251
6252 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6253 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006254 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006255 return(NULL);
6256 }
6257 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6258
Owen Taylor3473f882001-02-23 17:55:21 +00006259 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006260 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006261 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006262 if (ret->valueTab == NULL) {
6263 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006264 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006265 return(NULL);
6266 }
Owen Taylor3473f882001-02-23 17:55:21 +00006267 ret->valueNr = 0;
6268 ret->valueMax = 10;
6269 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006270 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006271
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006272 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006273 ret->comp = comp;
6274
Owen Taylor3473f882001-02-23 17:55:21 +00006275 return(ret);
6276}
6277
6278/**
6279 * xmlXPathFreeParserContext:
6280 * @ctxt: the context to free
6281 *
6282 * Free up an xmlXPathParserContext
6283 */
6284void
6285xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6286 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006287 xmlFree(ctxt->valueTab);
6288 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006289 if (ctxt->comp != NULL) {
6290#ifdef XPATH_STREAMING
6291 if (ctxt->comp->stream != NULL) {
6292 xmlFreePatternList(ctxt->comp->stream);
6293 ctxt->comp->stream = NULL;
6294 }
6295#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006296 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006297 }
Owen Taylor3473f882001-02-23 17:55:21 +00006298 xmlFree(ctxt);
6299}
6300
6301/************************************************************************
6302 * *
6303 * The implicit core function library *
6304 * *
6305 ************************************************************************/
6306
Owen Taylor3473f882001-02-23 17:55:21 +00006307/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006308 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006309 * @node: a node pointer
6310 *
6311 * Function computing the beginning of the string value of the node,
6312 * used to speed up comparisons
6313 *
6314 * Returns an int usable as a hash
6315 */
6316static unsigned int
6317xmlXPathNodeValHash(xmlNodePtr node) {
6318 int len = 2;
6319 const xmlChar * string = NULL;
6320 xmlNodePtr tmp = NULL;
6321 unsigned int ret = 0;
6322
6323 if (node == NULL)
6324 return(0);
6325
Daniel Veillard9adc0462003-03-24 18:39:54 +00006326 if (node->type == XML_DOCUMENT_NODE) {
6327 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6328 if (tmp == NULL)
6329 node = node->children;
6330 else
6331 node = tmp;
6332
6333 if (node == NULL)
6334 return(0);
6335 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006336
6337 switch (node->type) {
6338 case XML_COMMENT_NODE:
6339 case XML_PI_NODE:
6340 case XML_CDATA_SECTION_NODE:
6341 case XML_TEXT_NODE:
6342 string = node->content;
6343 if (string == NULL)
6344 return(0);
6345 if (string[0] == 0)
6346 return(0);
6347 return(((unsigned int) string[0]) +
6348 (((unsigned int) string[1]) << 8));
6349 case XML_NAMESPACE_DECL:
6350 string = ((xmlNsPtr)node)->href;
6351 if (string == NULL)
6352 return(0);
6353 if (string[0] == 0)
6354 return(0);
6355 return(((unsigned int) string[0]) +
6356 (((unsigned int) string[1]) << 8));
6357 case XML_ATTRIBUTE_NODE:
6358 tmp = ((xmlAttrPtr) node)->children;
6359 break;
6360 case XML_ELEMENT_NODE:
6361 tmp = node->children;
6362 break;
6363 default:
6364 return(0);
6365 }
6366 while (tmp != NULL) {
6367 switch (tmp->type) {
6368 case XML_COMMENT_NODE:
6369 case XML_PI_NODE:
6370 case XML_CDATA_SECTION_NODE:
6371 case XML_TEXT_NODE:
6372 string = tmp->content;
6373 break;
6374 case XML_NAMESPACE_DECL:
6375 string = ((xmlNsPtr)tmp)->href;
6376 break;
6377 default:
6378 break;
6379 }
6380 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006381 if (len == 1) {
6382 return(ret + (((unsigned int) string[0]) << 8));
6383 }
6384 if (string[1] == 0) {
6385 len = 1;
6386 ret = (unsigned int) string[0];
6387 } else {
6388 return(((unsigned int) string[0]) +
6389 (((unsigned int) string[1]) << 8));
6390 }
6391 }
6392 /*
6393 * Skip to next node
6394 */
6395 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6396 if (tmp->children->type != XML_ENTITY_DECL) {
6397 tmp = tmp->children;
6398 continue;
6399 }
6400 }
6401 if (tmp == node)
6402 break;
6403
6404 if (tmp->next != NULL) {
6405 tmp = tmp->next;
6406 continue;
6407 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006408
Daniel Veillardf06307e2001-07-03 10:35:50 +00006409 do {
6410 tmp = tmp->parent;
6411 if (tmp == NULL)
6412 break;
6413 if (tmp == node) {
6414 tmp = NULL;
6415 break;
6416 }
6417 if (tmp->next != NULL) {
6418 tmp = tmp->next;
6419 break;
6420 }
6421 } while (tmp != NULL);
6422 }
6423 return(ret);
6424}
6425
6426/**
6427 * xmlXPathStringHash:
6428 * @string: a string
6429 *
6430 * Function computing the beginning of the string value of the node,
6431 * used to speed up comparisons
6432 *
6433 * Returns an int usable as a hash
6434 */
6435static unsigned int
6436xmlXPathStringHash(const xmlChar * string) {
6437 if (string == NULL)
6438 return((unsigned int) 0);
6439 if (string[0] == 0)
6440 return(0);
6441 return(((unsigned int) string[0]) +
6442 (((unsigned int) string[1]) << 8));
6443}
6444
6445/**
Owen Taylor3473f882001-02-23 17:55:21 +00006446 * xmlXPathCompareNodeSetFloat:
6447 * @ctxt: the XPath Parser context
6448 * @inf: less than (1) or greater than (0)
6449 * @strict: is the comparison strict
6450 * @arg: the node set
6451 * @f: the value
6452 *
6453 * Implement the compare operation between a nodeset and a number
6454 * @ns < @val (1, 1, ...
6455 * @ns <= @val (1, 0, ...
6456 * @ns > @val (0, 1, ...
6457 * @ns >= @val (0, 0, ...
6458 *
6459 * If one object to be compared is a node-set and the other is a number,
6460 * then the comparison will be true if and only if there is a node in the
6461 * node-set such that the result of performing the comparison on the number
6462 * to be compared and on the result of converting the string-value of that
6463 * node to a number using the number function is true.
6464 *
6465 * Returns 0 or 1 depending on the results of the test.
6466 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006467static int
Owen Taylor3473f882001-02-23 17:55:21 +00006468xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6469 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6470 int i, ret = 0;
6471 xmlNodeSetPtr ns;
6472 xmlChar *str2;
6473
6474 if ((f == NULL) || (arg == NULL) ||
6475 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006476 xmlXPathReleaseObject(ctxt->context, arg);
6477 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006478 return(0);
6479 }
6480 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006481 if (ns != NULL) {
6482 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006483 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006484 if (str2 != NULL) {
6485 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006486 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006487 xmlFree(str2);
6488 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006489 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006490 ret = xmlXPathCompareValues(ctxt, inf, strict);
6491 if (ret)
6492 break;
6493 }
6494 }
Owen Taylor3473f882001-02-23 17:55:21 +00006495 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006496 xmlXPathReleaseObject(ctxt->context, arg);
6497 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006498 return(ret);
6499}
6500
6501/**
6502 * xmlXPathCompareNodeSetString:
6503 * @ctxt: the XPath Parser context
6504 * @inf: less than (1) or greater than (0)
6505 * @strict: is the comparison strict
6506 * @arg: the node set
6507 * @s: the value
6508 *
6509 * Implement the compare operation between a nodeset and a string
6510 * @ns < @val (1, 1, ...
6511 * @ns <= @val (1, 0, ...
6512 * @ns > @val (0, 1, ...
6513 * @ns >= @val (0, 0, ...
6514 *
6515 * If one object to be compared is a node-set and the other is a string,
6516 * then the comparison will be true if and only if there is a node in
6517 * the node-set such that the result of performing the comparison on the
6518 * string-value of the node and the other string is true.
6519 *
6520 * Returns 0 or 1 depending on the results of the test.
6521 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006522static int
Owen Taylor3473f882001-02-23 17:55:21 +00006523xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6524 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6525 int i, ret = 0;
6526 xmlNodeSetPtr ns;
6527 xmlChar *str2;
6528
6529 if ((s == NULL) || (arg == NULL) ||
6530 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006531 xmlXPathReleaseObject(ctxt->context, arg);
6532 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006533 return(0);
6534 }
6535 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006536 if (ns != NULL) {
6537 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006538 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006539 if (str2 != NULL) {
6540 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006541 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006542 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006543 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006544 ret = xmlXPathCompareValues(ctxt, inf, strict);
6545 if (ret)
6546 break;
6547 }
6548 }
Owen Taylor3473f882001-02-23 17:55:21 +00006549 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006550 xmlXPathReleaseObject(ctxt->context, arg);
6551 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006552 return(ret);
6553}
6554
6555/**
6556 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006557 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006558 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006559 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006560 * @arg2: the second node set object
6561 *
6562 * Implement the compare operation on nodesets:
6563 *
6564 * If both objects to be compared are node-sets, then the comparison
6565 * will be true if and only if there is a node in the first node-set
6566 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006567 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006568 * ....
6569 * When neither object to be compared is a node-set and the operator
6570 * is <=, <, >= or >, then the objects are compared by converting both
6571 * objects to numbers and comparing the numbers according to IEEE 754.
6572 * ....
6573 * The number function converts its argument to a number as follows:
6574 * - a string that consists of optional whitespace followed by an
6575 * optional minus sign followed by a Number followed by whitespace
6576 * is converted to the IEEE 754 number that is nearest (according
6577 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6578 * represented by the string; any other string is converted to NaN
6579 *
6580 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006581 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006582 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006583static int
6584xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006585 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6586 int i, j, init = 0;
6587 double val1;
6588 double *values2;
6589 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006590 xmlNodeSetPtr ns1;
6591 xmlNodeSetPtr ns2;
6592
6593 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006594 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6595 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006596 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006597 }
Owen Taylor3473f882001-02-23 17:55:21 +00006598 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006599 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6600 xmlXPathFreeObject(arg1);
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
6605 ns1 = arg1->nodesetval;
6606 ns2 = arg2->nodesetval;
6607
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006608 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006609 xmlXPathFreeObject(arg1);
6610 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006611 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006612 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006613 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006614 xmlXPathFreeObject(arg1);
6615 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006616 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006617 }
Owen Taylor3473f882001-02-23 17:55:21 +00006618
6619 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6620 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006621 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006622 xmlXPathFreeObject(arg1);
6623 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006624 return(0);
6625 }
6626 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006627 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006628 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006629 continue;
6630 for (j = 0;j < ns2->nodeNr;j++) {
6631 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006632 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006633 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006634 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006635 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006636 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006637 ret = (val1 < values2[j]);
6638 else if (inf && !strict)
6639 ret = (val1 <= values2[j]);
6640 else if (!inf && strict)
6641 ret = (val1 > values2[j]);
6642 else if (!inf && !strict)
6643 ret = (val1 >= values2[j]);
6644 if (ret)
6645 break;
6646 }
6647 if (ret)
6648 break;
6649 init = 1;
6650 }
6651 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006652 xmlXPathFreeObject(arg1);
6653 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006654 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006655}
6656
6657/**
6658 * xmlXPathCompareNodeSetValue:
6659 * @ctxt: the XPath Parser context
6660 * @inf: less than (1) or greater than (0)
6661 * @strict: is the comparison strict
6662 * @arg: the node set
6663 * @val: the value
6664 *
6665 * Implement the compare operation between a nodeset and a value
6666 * @ns < @val (1, 1, ...
6667 * @ns <= @val (1, 0, ...
6668 * @ns > @val (0, 1, ...
6669 * @ns >= @val (0, 0, ...
6670 *
6671 * If one object to be compared is a node-set and the other is a boolean,
6672 * then the comparison will be true if and only if the result of performing
6673 * the comparison on the boolean and on the result of converting
6674 * the node-set to a boolean using the boolean function is true.
6675 *
6676 * Returns 0 or 1 depending on the results of the test.
6677 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006678static int
Owen Taylor3473f882001-02-23 17:55:21 +00006679xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6680 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6681 if ((val == NULL) || (arg == NULL) ||
6682 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6683 return(0);
6684
6685 switch(val->type) {
6686 case XPATH_NUMBER:
6687 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6688 case XPATH_NODESET:
6689 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006690 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006691 case XPATH_STRING:
6692 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6693 case XPATH_BOOLEAN:
6694 valuePush(ctxt, arg);
6695 xmlXPathBooleanFunction(ctxt, 1);
6696 valuePush(ctxt, val);
6697 return(xmlXPathCompareValues(ctxt, inf, strict));
6698 default:
6699 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006700 }
6701 return(0);
6702}
6703
6704/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006705 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006706 * @arg: the nodeset object argument
6707 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006708 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006709 *
6710 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6711 * If one object to be compared is a node-set and the other is a string,
6712 * then the comparison will be true if and only if there is a node in
6713 * the node-set such that the result of performing the comparison on the
6714 * string-value of the node and the other string is true.
6715 *
6716 * Returns 0 or 1 depending on the results of the test.
6717 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006718static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006719xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006720{
Owen Taylor3473f882001-02-23 17:55:21 +00006721 int i;
6722 xmlNodeSetPtr ns;
6723 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006724 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006725
6726 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006727 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6728 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006729 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006730 /*
6731 * A NULL nodeset compared with a string is always false
6732 * (since there is no node equal, and no node not equal)
6733 */
6734 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006735 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006736 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006737 for (i = 0; i < ns->nodeNr; i++) {
6738 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6739 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6740 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6741 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006742 if (neq)
6743 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006744 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006745 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6746 if (neq)
6747 continue;
6748 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006749 } else if (neq) {
6750 if (str2 != NULL)
6751 xmlFree(str2);
6752 return (1);
6753 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006754 if (str2 != NULL)
6755 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006756 } else if (neq)
6757 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006758 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006759 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006760}
6761
6762/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006763 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006764 * @arg: the nodeset object argument
6765 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006766 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006767 *
6768 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6769 * If one object to be compared is a node-set and the other is a number,
6770 * then the comparison will be true if and only if there is a node in
6771 * the node-set such that the result of performing the comparison on the
6772 * number to be compared and on the result of converting the string-value
6773 * of that node to a number using the number function is true.
6774 *
6775 * Returns 0 or 1 depending on the results of the test.
6776 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006777static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006778xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6779 xmlXPathObjectPtr arg, double f, int neq) {
6780 int i, ret=0;
6781 xmlNodeSetPtr ns;
6782 xmlChar *str2;
6783 xmlXPathObjectPtr val;
6784 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006785
6786 if ((arg == NULL) ||
6787 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6788 return(0);
6789
William M. Brack0c022ad2002-07-12 00:56:01 +00006790 ns = arg->nodesetval;
6791 if (ns != NULL) {
6792 for (i=0;i<ns->nodeNr;i++) {
6793 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6794 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006795 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006796 xmlFree(str2);
6797 xmlXPathNumberFunction(ctxt, 1);
6798 val = valuePop(ctxt);
6799 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006800 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006801 if (!xmlXPathIsNaN(v)) {
6802 if ((!neq) && (v==f)) {
6803 ret = 1;
6804 break;
6805 } else if ((neq) && (v!=f)) {
6806 ret = 1;
6807 break;
6808 }
William M. Brack32f0f712005-07-14 07:00:33 +00006809 } else { /* NaN is unequal to any value */
6810 if (neq)
6811 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006812 }
6813 }
6814 }
6815 }
6816
6817 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006818}
6819
6820
6821/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006822 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006823 * @arg1: first nodeset object argument
6824 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006825 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006826 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006827 * Implement the equal / not equal operation on XPath nodesets:
6828 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006829 * If both objects to be compared are node-sets, then the comparison
6830 * will be true if and only if there is a node in the first node-set and
6831 * a node in the second node-set such that the result of performing the
6832 * comparison on the string-values of the two nodes is true.
6833 *
6834 * (needless to say, this is a costly operation)
6835 *
6836 * Returns 0 or 1 depending on the results of the test.
6837 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006838static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006839xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006840 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006841 unsigned int *hashs1;
6842 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006843 xmlChar **values1;
6844 xmlChar **values2;
6845 int ret = 0;
6846 xmlNodeSetPtr ns1;
6847 xmlNodeSetPtr ns2;
6848
6849 if ((arg1 == NULL) ||
6850 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6851 return(0);
6852 if ((arg2 == NULL) ||
6853 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6854 return(0);
6855
6856 ns1 = arg1->nodesetval;
6857 ns2 = arg2->nodesetval;
6858
Daniel Veillard911f49a2001-04-07 15:39:35 +00006859 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006860 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006861 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006862 return(0);
6863
6864 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006865 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006866 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006867 if (neq == 0)
6868 for (i = 0;i < ns1->nodeNr;i++)
6869 for (j = 0;j < ns2->nodeNr;j++)
6870 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6871 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006872
6873 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006874 if (values1 == NULL) {
6875 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006876 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006877 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006878 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6879 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006880 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006881 xmlFree(values1);
6882 return(0);
6883 }
Owen Taylor3473f882001-02-23 17:55:21 +00006884 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6885 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6886 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006887 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006888 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006889 xmlFree(values1);
6890 return(0);
6891 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006892 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6893 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006894 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006895 xmlFree(hashs1);
6896 xmlFree(values1);
6897 xmlFree(values2);
6898 return(0);
6899 }
Owen Taylor3473f882001-02-23 17:55:21 +00006900 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6901 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006902 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006903 for (j = 0;j < ns2->nodeNr;j++) {
6904 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006905 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006906 if (hashs1[i] != hashs2[j]) {
6907 if (neq) {
6908 ret = 1;
6909 break;
6910 }
6911 }
6912 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006913 if (values1[i] == NULL)
6914 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6915 if (values2[j] == NULL)
6916 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006917 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006918 if (ret)
6919 break;
6920 }
Owen Taylor3473f882001-02-23 17:55:21 +00006921 }
6922 if (ret)
6923 break;
6924 }
6925 for (i = 0;i < ns1->nodeNr;i++)
6926 if (values1[i] != NULL)
6927 xmlFree(values1[i]);
6928 for (j = 0;j < ns2->nodeNr;j++)
6929 if (values2[j] != NULL)
6930 xmlFree(values2[j]);
6931 xmlFree(values1);
6932 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006933 xmlFree(hashs1);
6934 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006935 return(ret);
6936}
6937
William M. Brack0c022ad2002-07-12 00:56:01 +00006938static int
6939xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6940 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006941 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006942 /*
6943 *At this point we are assured neither arg1 nor arg2
6944 *is a nodeset, so we can just pick the appropriate routine.
6945 */
Owen Taylor3473f882001-02-23 17:55:21 +00006946 switch (arg1->type) {
6947 case XPATH_UNDEFINED:
6948#ifdef DEBUG_EXPR
6949 xmlGenericError(xmlGenericErrorContext,
6950 "Equal: undefined\n");
6951#endif
6952 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006953 case XPATH_BOOLEAN:
6954 switch (arg2->type) {
6955 case XPATH_UNDEFINED:
6956#ifdef DEBUG_EXPR
6957 xmlGenericError(xmlGenericErrorContext,
6958 "Equal: undefined\n");
6959#endif
6960 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006961 case XPATH_BOOLEAN:
6962#ifdef DEBUG_EXPR
6963 xmlGenericError(xmlGenericErrorContext,
6964 "Equal: %d boolean %d \n",
6965 arg1->boolval, arg2->boolval);
6966#endif
6967 ret = (arg1->boolval == arg2->boolval);
6968 break;
6969 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006970 ret = (arg1->boolval ==
6971 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006972 break;
6973 case XPATH_STRING:
6974 if ((arg2->stringval == NULL) ||
6975 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006976 else
Owen Taylor3473f882001-02-23 17:55:21 +00006977 ret = 1;
6978 ret = (arg1->boolval == ret);
6979 break;
6980 case XPATH_USERS:
6981 case XPATH_POINT:
6982 case XPATH_RANGE:
6983 case XPATH_LOCATIONSET:
6984 TODO
6985 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006986 case XPATH_NODESET:
6987 case XPATH_XSLT_TREE:
6988 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006989 }
6990 break;
6991 case XPATH_NUMBER:
6992 switch (arg2->type) {
6993 case XPATH_UNDEFINED:
6994#ifdef DEBUG_EXPR
6995 xmlGenericError(xmlGenericErrorContext,
6996 "Equal: undefined\n");
6997#endif
6998 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006999 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00007000 ret = (arg2->boolval==
7001 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007002 break;
7003 case XPATH_STRING:
7004 valuePush(ctxt, arg2);
7005 xmlXPathNumberFunction(ctxt, 1);
7006 arg2 = valuePop(ctxt);
7007 /* no break on purpose */
7008 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007009 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007010 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007011 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007012 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007013 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7014 if (xmlXPathIsInf(arg2->floatval) == 1)
7015 ret = 1;
7016 else
7017 ret = 0;
7018 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7019 if (xmlXPathIsInf(arg2->floatval) == -1)
7020 ret = 1;
7021 else
7022 ret = 0;
7023 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7024 if (xmlXPathIsInf(arg1->floatval) == 1)
7025 ret = 1;
7026 else
7027 ret = 0;
7028 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7029 if (xmlXPathIsInf(arg1->floatval) == -1)
7030 ret = 1;
7031 else
7032 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007033 } else {
7034 ret = (arg1->floatval == arg2->floatval);
7035 }
Owen Taylor3473f882001-02-23 17:55:21 +00007036 break;
7037 case XPATH_USERS:
7038 case XPATH_POINT:
7039 case XPATH_RANGE:
7040 case XPATH_LOCATIONSET:
7041 TODO
7042 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007043 case XPATH_NODESET:
7044 case XPATH_XSLT_TREE:
7045 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007046 }
7047 break;
7048 case XPATH_STRING:
7049 switch (arg2->type) {
7050 case XPATH_UNDEFINED:
7051#ifdef DEBUG_EXPR
7052 xmlGenericError(xmlGenericErrorContext,
7053 "Equal: undefined\n");
7054#endif
7055 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007056 case XPATH_BOOLEAN:
7057 if ((arg1->stringval == NULL) ||
7058 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007059 else
Owen Taylor3473f882001-02-23 17:55:21 +00007060 ret = 1;
7061 ret = (arg2->boolval == ret);
7062 break;
7063 case XPATH_STRING:
7064 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7065 break;
7066 case XPATH_NUMBER:
7067 valuePush(ctxt, arg1);
7068 xmlXPathNumberFunction(ctxt, 1);
7069 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007070 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007071 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007072 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007073 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007074 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7075 if (xmlXPathIsInf(arg2->floatval) == 1)
7076 ret = 1;
7077 else
7078 ret = 0;
7079 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7080 if (xmlXPathIsInf(arg2->floatval) == -1)
7081 ret = 1;
7082 else
7083 ret = 0;
7084 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7085 if (xmlXPathIsInf(arg1->floatval) == 1)
7086 ret = 1;
7087 else
7088 ret = 0;
7089 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7090 if (xmlXPathIsInf(arg1->floatval) == -1)
7091 ret = 1;
7092 else
7093 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007094 } else {
7095 ret = (arg1->floatval == arg2->floatval);
7096 }
Owen Taylor3473f882001-02-23 17:55:21 +00007097 break;
7098 case XPATH_USERS:
7099 case XPATH_POINT:
7100 case XPATH_RANGE:
7101 case XPATH_LOCATIONSET:
7102 TODO
7103 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007104 case XPATH_NODESET:
7105 case XPATH_XSLT_TREE:
7106 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007107 }
7108 break;
7109 case XPATH_USERS:
7110 case XPATH_POINT:
7111 case XPATH_RANGE:
7112 case XPATH_LOCATIONSET:
7113 TODO
7114 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007115 case XPATH_NODESET:
7116 case XPATH_XSLT_TREE:
7117 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007118 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007119 xmlXPathReleaseObject(ctxt->context, arg1);
7120 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007121 return(ret);
7122}
7123
William M. Brack0c022ad2002-07-12 00:56:01 +00007124/**
7125 * xmlXPathEqualValues:
7126 * @ctxt: the XPath Parser context
7127 *
7128 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7129 *
7130 * Returns 0 or 1 depending on the results of the test.
7131 */
7132int
7133xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7134 xmlXPathObjectPtr arg1, arg2, argtmp;
7135 int ret = 0;
7136
Daniel Veillard6128c012004-11-08 17:16:15 +00007137 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007138 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007139 arg1 = valuePop(ctxt);
7140 if ((arg1 == NULL) || (arg2 == NULL)) {
7141 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007142 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007143 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007144 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007145 XP_ERROR0(XPATH_INVALID_OPERAND);
7146 }
7147
7148 if (arg1 == arg2) {
7149#ifdef DEBUG_EXPR
7150 xmlGenericError(xmlGenericErrorContext,
7151 "Equal: by pointer\n");
7152#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007153 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007154 return(1);
7155 }
7156
7157 /*
7158 *If either argument is a nodeset, it's a 'special case'
7159 */
7160 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7161 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7162 /*
7163 *Hack it to assure arg1 is the nodeset
7164 */
7165 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7166 argtmp = arg2;
7167 arg2 = arg1;
7168 arg1 = argtmp;
7169 }
7170 switch (arg2->type) {
7171 case XPATH_UNDEFINED:
7172#ifdef DEBUG_EXPR
7173 xmlGenericError(xmlGenericErrorContext,
7174 "Equal: undefined\n");
7175#endif
7176 break;
7177 case XPATH_NODESET:
7178 case XPATH_XSLT_TREE:
7179 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7180 break;
7181 case XPATH_BOOLEAN:
7182 if ((arg1->nodesetval == NULL) ||
7183 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007184 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007185 ret = 1;
7186 ret = (ret == arg2->boolval);
7187 break;
7188 case XPATH_NUMBER:
7189 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7190 break;
7191 case XPATH_STRING:
7192 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7193 break;
7194 case XPATH_USERS:
7195 case XPATH_POINT:
7196 case XPATH_RANGE:
7197 case XPATH_LOCATIONSET:
7198 TODO
7199 break;
7200 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007201 xmlXPathReleaseObject(ctxt->context, arg1);
7202 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007203 return(ret);
7204 }
7205
7206 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7207}
7208
7209/**
7210 * xmlXPathNotEqualValues:
7211 * @ctxt: the XPath Parser context
7212 *
7213 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7214 *
7215 * Returns 0 or 1 depending on the results of the test.
7216 */
7217int
7218xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7219 xmlXPathObjectPtr arg1, arg2, argtmp;
7220 int ret = 0;
7221
Daniel Veillard6128c012004-11-08 17:16:15 +00007222 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007223 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007224 arg1 = valuePop(ctxt);
7225 if ((arg1 == NULL) || (arg2 == NULL)) {
7226 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007227 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007228 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007229 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007230 XP_ERROR0(XPATH_INVALID_OPERAND);
7231 }
7232
7233 if (arg1 == arg2) {
7234#ifdef DEBUG_EXPR
7235 xmlGenericError(xmlGenericErrorContext,
7236 "NotEqual: by pointer\n");
7237#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007238 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007239 return(0);
7240 }
7241
7242 /*
7243 *If either argument is a nodeset, it's a 'special case'
7244 */
7245 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7246 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7247 /*
7248 *Hack it to assure arg1 is the nodeset
7249 */
7250 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7251 argtmp = arg2;
7252 arg2 = arg1;
7253 arg1 = argtmp;
7254 }
7255 switch (arg2->type) {
7256 case XPATH_UNDEFINED:
7257#ifdef DEBUG_EXPR
7258 xmlGenericError(xmlGenericErrorContext,
7259 "NotEqual: undefined\n");
7260#endif
7261 break;
7262 case XPATH_NODESET:
7263 case XPATH_XSLT_TREE:
7264 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7265 break;
7266 case XPATH_BOOLEAN:
7267 if ((arg1->nodesetval == NULL) ||
7268 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007269 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007270 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007271 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007272 break;
7273 case XPATH_NUMBER:
7274 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7275 break;
7276 case XPATH_STRING:
7277 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7278 break;
7279 case XPATH_USERS:
7280 case XPATH_POINT:
7281 case XPATH_RANGE:
7282 case XPATH_LOCATIONSET:
7283 TODO
7284 break;
7285 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007286 xmlXPathReleaseObject(ctxt->context, arg1);
7287 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007288 return(ret);
7289 }
7290
7291 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7292}
Owen Taylor3473f882001-02-23 17:55:21 +00007293
7294/**
7295 * xmlXPathCompareValues:
7296 * @ctxt: the XPath Parser context
7297 * @inf: less than (1) or greater than (0)
7298 * @strict: is the comparison strict
7299 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007300 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007301 * @arg1 < @arg2 (1, 1, ...
7302 * @arg1 <= @arg2 (1, 0, ...
7303 * @arg1 > @arg2 (0, 1, ...
7304 * @arg1 >= @arg2 (0, 0, ...
7305 *
7306 * When neither object to be compared is a node-set and the operator is
7307 * <=, <, >=, >, then the objects are compared by converted both objects
7308 * to numbers and comparing the numbers according to IEEE 754. The <
7309 * comparison will be true if and only if the first number is less than the
7310 * second number. The <= comparison will be true if and only if the first
7311 * number is less than or equal to the second number. The > comparison
7312 * will be true if and only if the first number is greater than the second
7313 * number. The >= comparison will be true if and only if the first number
7314 * is greater than or equal to the second number.
7315 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007316 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007317 */
7318int
7319xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007320 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007321 xmlXPathObjectPtr arg1, arg2;
7322
Daniel Veillard6128c012004-11-08 17:16:15 +00007323 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007324 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007325 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007326 if ((arg1 == NULL) || (arg2 == NULL)) {
7327 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007328 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007329 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007330 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007331 XP_ERROR0(XPATH_INVALID_OPERAND);
7332 }
7333
William M. Brack0c022ad2002-07-12 00:56:01 +00007334 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7335 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007336 /*
7337 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7338 * are not freed from within this routine; they will be freed from the
7339 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7340 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007341 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7342 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007343 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007344 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007345 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007346 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7347 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007348 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007349 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7350 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007351 }
7352 }
7353 return(ret);
7354 }
7355
7356 if (arg1->type != XPATH_NUMBER) {
7357 valuePush(ctxt, arg1);
7358 xmlXPathNumberFunction(ctxt, 1);
7359 arg1 = valuePop(ctxt);
7360 }
7361 if (arg1->type != XPATH_NUMBER) {
7362 xmlXPathFreeObject(arg1);
7363 xmlXPathFreeObject(arg2);
7364 XP_ERROR0(XPATH_INVALID_OPERAND);
7365 }
7366 if (arg2->type != XPATH_NUMBER) {
7367 valuePush(ctxt, arg2);
7368 xmlXPathNumberFunction(ctxt, 1);
7369 arg2 = valuePop(ctxt);
7370 }
7371 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007372 xmlXPathReleaseObject(ctxt->context, arg1);
7373 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007374 XP_ERROR0(XPATH_INVALID_OPERAND);
7375 }
7376 /*
7377 * Add tests for infinity and nan
7378 * => feedback on 3.4 for Inf and NaN
7379 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007380 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007381 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007382 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007383 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007384 arg1i=xmlXPathIsInf(arg1->floatval);
7385 arg2i=xmlXPathIsInf(arg2->floatval);
7386 if (inf && strict) {
7387 if ((arg1i == -1 && arg2i != -1) ||
7388 (arg2i == 1 && arg1i != 1)) {
7389 ret = 1;
7390 } else if (arg1i == 0 && arg2i == 0) {
7391 ret = (arg1->floatval < arg2->floatval);
7392 } else {
7393 ret = 0;
7394 }
7395 }
7396 else if (inf && !strict) {
7397 if (arg1i == -1 || arg2i == 1) {
7398 ret = 1;
7399 } else if (arg1i == 0 && arg2i == 0) {
7400 ret = (arg1->floatval <= arg2->floatval);
7401 } else {
7402 ret = 0;
7403 }
7404 }
7405 else if (!inf && strict) {
7406 if ((arg1i == 1 && arg2i != 1) ||
7407 (arg2i == -1 && arg1i != -1)) {
7408 ret = 1;
7409 } else if (arg1i == 0 && arg2i == 0) {
7410 ret = (arg1->floatval > arg2->floatval);
7411 } else {
7412 ret = 0;
7413 }
7414 }
7415 else if (!inf && !strict) {
7416 if (arg1i == 1 || arg2i == -1) {
7417 ret = 1;
7418 } else if (arg1i == 0 && arg2i == 0) {
7419 ret = (arg1->floatval >= arg2->floatval);
7420 } else {
7421 ret = 0;
7422 }
7423 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007424 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007425 xmlXPathReleaseObject(ctxt->context, arg1);
7426 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007427 return(ret);
7428}
7429
7430/**
7431 * xmlXPathValueFlipSign:
7432 * @ctxt: the XPath Parser context
7433 *
7434 * Implement the unary - operation on an XPath object
7435 * The numeric operators convert their operands to numbers as if
7436 * by calling the number function.
7437 */
7438void
7439xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007440 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007441 CAST_TO_NUMBER;
7442 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007443 if (xmlXPathIsNaN(ctxt->value->floatval))
7444 ctxt->value->floatval=xmlXPathNAN;
7445 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7446 ctxt->value->floatval=xmlXPathNINF;
7447 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7448 ctxt->value->floatval=xmlXPathPINF;
7449 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007450 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7451 ctxt->value->floatval = xmlXPathNZERO;
7452 else
7453 ctxt->value->floatval = 0;
7454 }
7455 else
7456 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007457}
7458
7459/**
7460 * xmlXPathAddValues:
7461 * @ctxt: the XPath Parser context
7462 *
7463 * Implement the add operation on XPath objects:
7464 * The numeric operators convert their operands to numbers as if
7465 * by calling the number function.
7466 */
7467void
7468xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7469 xmlXPathObjectPtr arg;
7470 double val;
7471
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007472 arg = valuePop(ctxt);
7473 if (arg == NULL)
7474 XP_ERROR(XPATH_INVALID_OPERAND);
7475 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007476 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007477 CAST_TO_NUMBER;
7478 CHECK_TYPE(XPATH_NUMBER);
7479 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007480}
7481
7482/**
7483 * xmlXPathSubValues:
7484 * @ctxt: the XPath Parser context
7485 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007486 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007487 * The numeric operators convert their operands to numbers as if
7488 * by calling the number function.
7489 */
7490void
7491xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7492 xmlXPathObjectPtr arg;
7493 double val;
7494
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007495 arg = valuePop(ctxt);
7496 if (arg == NULL)
7497 XP_ERROR(XPATH_INVALID_OPERAND);
7498 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007499 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007500 CAST_TO_NUMBER;
7501 CHECK_TYPE(XPATH_NUMBER);
7502 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007503}
7504
7505/**
7506 * xmlXPathMultValues:
7507 * @ctxt: the XPath Parser context
7508 *
7509 * Implement the multiply operation on XPath objects:
7510 * The numeric operators convert their operands to numbers as if
7511 * by calling the number function.
7512 */
7513void
7514xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7515 xmlXPathObjectPtr arg;
7516 double val;
7517
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007518 arg = valuePop(ctxt);
7519 if (arg == NULL)
7520 XP_ERROR(XPATH_INVALID_OPERAND);
7521 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007522 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007523 CAST_TO_NUMBER;
7524 CHECK_TYPE(XPATH_NUMBER);
7525 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007526}
7527
7528/**
7529 * xmlXPathDivValues:
7530 * @ctxt: the XPath Parser context
7531 *
7532 * Implement the div operation on XPath objects @arg1 / @arg2:
7533 * The numeric operators convert their operands to numbers as if
7534 * by calling the number function.
7535 */
7536void
7537xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7538 xmlXPathObjectPtr arg;
7539 double val;
7540
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007541 arg = valuePop(ctxt);
7542 if (arg == NULL)
7543 XP_ERROR(XPATH_INVALID_OPERAND);
7544 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007545 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007546 CAST_TO_NUMBER;
7547 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007548 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7549 ctxt->value->floatval = xmlXPathNAN;
7550 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007551 if (ctxt->value->floatval == 0)
7552 ctxt->value->floatval = xmlXPathNAN;
7553 else if (ctxt->value->floatval > 0)
7554 ctxt->value->floatval = xmlXPathNINF;
7555 else if (ctxt->value->floatval < 0)
7556 ctxt->value->floatval = xmlXPathPINF;
7557 }
7558 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007559 if (ctxt->value->floatval == 0)
7560 ctxt->value->floatval = xmlXPathNAN;
7561 else if (ctxt->value->floatval > 0)
7562 ctxt->value->floatval = xmlXPathPINF;
7563 else if (ctxt->value->floatval < 0)
7564 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007565 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007566 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007567}
7568
7569/**
7570 * xmlXPathModValues:
7571 * @ctxt: the XPath Parser context
7572 *
7573 * Implement the mod operation on XPath objects: @arg1 / @arg2
7574 * The numeric operators convert their operands to numbers as if
7575 * by calling the number function.
7576 */
7577void
7578xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7579 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007580 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007581
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007582 arg = valuePop(ctxt);
7583 if (arg == NULL)
7584 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007585 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007586 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007587 CAST_TO_NUMBER;
7588 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007589 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007590 if (arg2 == 0)
7591 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007592 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007593 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007594 }
Owen Taylor3473f882001-02-23 17:55:21 +00007595}
7596
7597/************************************************************************
7598 * *
7599 * The traversal functions *
7600 * *
7601 ************************************************************************/
7602
Owen Taylor3473f882001-02-23 17:55:21 +00007603/*
7604 * A traversal function enumerates nodes along an axis.
7605 * Initially it must be called with NULL, and it indicates
7606 * termination on the axis by returning NULL.
7607 */
7608typedef xmlNodePtr (*xmlXPathTraversalFunction)
7609 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7610
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007611/*
7612 * xmlXPathTraversalFunctionExt:
7613 * A traversal function enumerates nodes along an axis.
7614 * Initially it must be called with NULL, and it indicates
7615 * termination on the axis by returning NULL.
7616 * The context node of the traversal is specified via @contextNode.
7617 */
7618typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7619 (xmlNodePtr cur, xmlNodePtr contextNode);
7620
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007621/*
7622 * xmlXPathNodeSetMergeFunction:
7623 * Used for merging node sets in xmlXPathCollectAndTest().
7624 */
7625typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7626 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7627
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007628
Owen Taylor3473f882001-02-23 17:55:21 +00007629/**
7630 * xmlXPathNextSelf:
7631 * @ctxt: the XPath Parser context
7632 * @cur: the current node in the traversal
7633 *
7634 * Traversal function for the "self" direction
7635 * The self axis contains just the context node itself
7636 *
7637 * Returns the next element following that axis
7638 */
7639xmlNodePtr
7640xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007641 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007642 if (cur == NULL)
7643 return(ctxt->context->node);
7644 return(NULL);
7645}
7646
7647/**
7648 * xmlXPathNextChild:
7649 * @ctxt: the XPath Parser context
7650 * @cur: the current node in the traversal
7651 *
7652 * Traversal function for the "child" direction
7653 * The child axis contains the children of the context node in document order.
7654 *
7655 * Returns the next element following that axis
7656 */
7657xmlNodePtr
7658xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007659 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007660 if (cur == NULL) {
7661 if (ctxt->context->node == NULL) return(NULL);
7662 switch (ctxt->context->node->type) {
7663 case XML_ELEMENT_NODE:
7664 case XML_TEXT_NODE:
7665 case XML_CDATA_SECTION_NODE:
7666 case XML_ENTITY_REF_NODE:
7667 case XML_ENTITY_NODE:
7668 case XML_PI_NODE:
7669 case XML_COMMENT_NODE:
7670 case XML_NOTATION_NODE:
7671 case XML_DTD_NODE:
7672 return(ctxt->context->node->children);
7673 case XML_DOCUMENT_NODE:
7674 case XML_DOCUMENT_TYPE_NODE:
7675 case XML_DOCUMENT_FRAG_NODE:
7676 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007677#ifdef LIBXML_DOCB_ENABLED
7678 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007679#endif
7680 return(((xmlDocPtr) ctxt->context->node)->children);
7681 case XML_ELEMENT_DECL:
7682 case XML_ATTRIBUTE_DECL:
7683 case XML_ENTITY_DECL:
7684 case XML_ATTRIBUTE_NODE:
7685 case XML_NAMESPACE_DECL:
7686 case XML_XINCLUDE_START:
7687 case XML_XINCLUDE_END:
7688 return(NULL);
7689 }
7690 return(NULL);
7691 }
7692 if ((cur->type == XML_DOCUMENT_NODE) ||
7693 (cur->type == XML_HTML_DOCUMENT_NODE))
7694 return(NULL);
7695 return(cur->next);
7696}
7697
7698/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007699 * xmlXPathNextChildElement:
7700 * @ctxt: the XPath Parser context
7701 * @cur: the current node in the traversal
7702 *
7703 * Traversal function for the "child" direction and nodes of type element.
7704 * The child axis contains the children of the context node in document order.
7705 *
7706 * Returns the next element following that axis
7707 */
7708static xmlNodePtr
7709xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7710 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7711 if (cur == NULL) {
7712 cur = ctxt->context->node;
7713 if (cur == NULL) return(NULL);
7714 /*
7715 * Get the first element child.
7716 */
7717 switch (cur->type) {
7718 case XML_ELEMENT_NODE:
7719 case XML_DOCUMENT_FRAG_NODE:
7720 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7721 case XML_ENTITY_NODE:
7722 cur = cur->children;
7723 if (cur != NULL) {
7724 if (cur->type == XML_ELEMENT_NODE)
7725 return(cur);
7726 do {
7727 cur = cur->next;
7728 } while ((cur != NULL) &&
7729 (cur->type != XML_ELEMENT_NODE));
7730 return(cur);
7731 }
7732 return(NULL);
7733 case XML_DOCUMENT_NODE:
7734 case XML_HTML_DOCUMENT_NODE:
7735#ifdef LIBXML_DOCB_ENABLED
7736 case XML_DOCB_DOCUMENT_NODE:
7737#endif
7738 return(xmlDocGetRootElement((xmlDocPtr) cur));
7739 default:
7740 return(NULL);
7741 }
7742 return(NULL);
7743 }
7744 /*
7745 * Get the next sibling element node.
7746 */
7747 switch (cur->type) {
7748 case XML_ELEMENT_NODE:
7749 case XML_TEXT_NODE:
7750 case XML_ENTITY_REF_NODE:
7751 case XML_ENTITY_NODE:
7752 case XML_CDATA_SECTION_NODE:
7753 case XML_PI_NODE:
7754 case XML_COMMENT_NODE:
7755 case XML_XINCLUDE_END:
7756 break;
7757 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7758 default:
7759 return(NULL);
7760 }
7761 if (cur->next != NULL) {
7762 if (cur->next->type == XML_ELEMENT_NODE)
7763 return(cur->next);
7764 cur = cur->next;
7765 do {
7766 cur = cur->next;
7767 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7768 return(cur);
7769 }
7770 return(NULL);
7771}
7772
7773/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007774 * xmlXPathNextDescendantOrSelfElemParent:
7775 * @ctxt: the XPath Parser context
7776 * @cur: the current node in the traversal
7777 *
7778 * Traversal function for the "descendant-or-self" axis.
7779 * Additionally it returns only nodes which can be parents of
7780 * element nodes.
7781 *
7782 *
7783 * Returns the next element following that axis
7784 */
7785static xmlNodePtr
7786xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7787 xmlNodePtr contextNode)
7788{
7789 if (cur == NULL) {
7790 if (contextNode == NULL)
7791 return(NULL);
7792 switch (contextNode->type) {
7793 case XML_ELEMENT_NODE:
7794 case XML_XINCLUDE_START:
7795 case XML_DOCUMENT_FRAG_NODE:
7796 case XML_DOCUMENT_NODE:
7797#ifdef LIBXML_DOCB_ENABLED
7798 case XML_DOCB_DOCUMENT_NODE:
7799#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00007800 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007801 return(contextNode);
7802 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007803 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007804 }
7805 return(NULL);
7806 } else {
7807 xmlNodePtr start = cur;
7808
7809 while (cur != NULL) {
7810 switch (cur->type) {
7811 case XML_ELEMENT_NODE:
7812 /* TODO: OK to have XInclude here? */
7813 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007814 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007815 if (cur != start)
7816 return(cur);
7817 if (cur->children != NULL) {
7818 cur = cur->children;
7819 continue;
7820 }
7821 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007822 /* Not sure if we need those here. */
7823 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007824#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007825 case XML_DOCB_DOCUMENT_NODE:
7826#endif
7827 case XML_HTML_DOCUMENT_NODE:
7828 if (cur != start)
7829 return(cur);
7830 return(xmlDocGetRootElement((xmlDocPtr) cur));
7831 default:
7832 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007833 }
7834
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007835next_sibling:
7836 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007837 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007838 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007839 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007840 } else {
7841 cur = cur->parent;
7842 goto next_sibling;
7843 }
7844 }
7845 }
7846 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007847}
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007848
7849/**
Owen Taylor3473f882001-02-23 17:55:21 +00007850 * xmlXPathNextDescendant:
7851 * @ctxt: the XPath Parser context
7852 * @cur: the current node in the traversal
7853 *
7854 * Traversal function for the "descendant" direction
7855 * the descendant axis contains the descendants of the context node in document
7856 * order; a descendant is a child or a child of a child and so on.
7857 *
7858 * Returns the next element following that axis
7859 */
7860xmlNodePtr
7861xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007862 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007863 if (cur == NULL) {
7864 if (ctxt->context->node == NULL)
7865 return(NULL);
7866 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7867 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7868 return(NULL);
7869
7870 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7871 return(ctxt->context->doc->children);
7872 return(ctxt->context->node->children);
7873 }
7874
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007875 if (cur->type == XML_NAMESPACE_DECL)
7876 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007877 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007878 /*
7879 * Do not descend on entities declarations
7880 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007881 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007882 cur = cur->children;
7883 /*
7884 * Skip DTDs
7885 */
7886 if (cur->type != XML_DTD_NODE)
7887 return(cur);
7888 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007889 }
7890
7891 if (cur == ctxt->context->node) return(NULL);
7892
Daniel Veillard68e9e742002-11-16 15:35:11 +00007893 while (cur->next != NULL) {
7894 cur = cur->next;
7895 if ((cur->type != XML_ENTITY_DECL) &&
7896 (cur->type != XML_DTD_NODE))
7897 return(cur);
7898 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007899
Owen Taylor3473f882001-02-23 17:55:21 +00007900 do {
7901 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007902 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007903 if (cur == ctxt->context->node) return(NULL);
7904 if (cur->next != NULL) {
7905 cur = cur->next;
7906 return(cur);
7907 }
7908 } while (cur != NULL);
7909 return(cur);
7910}
7911
7912/**
7913 * xmlXPathNextDescendantOrSelf:
7914 * @ctxt: the XPath Parser context
7915 * @cur: the current node in the traversal
7916 *
7917 * Traversal function for the "descendant-or-self" direction
7918 * the descendant-or-self axis contains the context node and the descendants
7919 * of the context node in document order; thus the context node is the first
7920 * node on the axis, and the first child of the context node is the second node
7921 * on the axis
7922 *
7923 * Returns the next element following that axis
7924 */
7925xmlNodePtr
7926xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007927 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007928 if (cur == NULL) {
7929 if (ctxt->context->node == NULL)
7930 return(NULL);
7931 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7932 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7933 return(NULL);
7934 return(ctxt->context->node);
7935 }
7936
7937 return(xmlXPathNextDescendant(ctxt, cur));
7938}
7939
7940/**
7941 * xmlXPathNextParent:
7942 * @ctxt: the XPath Parser context
7943 * @cur: the current node in the traversal
7944 *
7945 * Traversal function for the "parent" direction
7946 * The parent axis contains the parent of the context node, if there is one.
7947 *
7948 * Returns the next element following that axis
7949 */
7950xmlNodePtr
7951xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007952 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007953 /*
7954 * the parent of an attribute or namespace node is the element
7955 * to which the attribute or namespace node is attached
7956 * Namespace handling !!!
7957 */
7958 if (cur == NULL) {
7959 if (ctxt->context->node == NULL) return(NULL);
7960 switch (ctxt->context->node->type) {
7961 case XML_ELEMENT_NODE:
7962 case XML_TEXT_NODE:
7963 case XML_CDATA_SECTION_NODE:
7964 case XML_ENTITY_REF_NODE:
7965 case XML_ENTITY_NODE:
7966 case XML_PI_NODE:
7967 case XML_COMMENT_NODE:
7968 case XML_NOTATION_NODE:
7969 case XML_DTD_NODE:
7970 case XML_ELEMENT_DECL:
7971 case XML_ATTRIBUTE_DECL:
7972 case XML_XINCLUDE_START:
7973 case XML_XINCLUDE_END:
7974 case XML_ENTITY_DECL:
7975 if (ctxt->context->node->parent == NULL)
7976 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007977 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007978 ((ctxt->context->node->parent->name[0] == ' ') ||
7979 (xmlStrEqual(ctxt->context->node->parent->name,
7980 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007981 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007982 return(ctxt->context->node->parent);
7983 case XML_ATTRIBUTE_NODE: {
7984 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7985
7986 return(att->parent);
7987 }
7988 case XML_DOCUMENT_NODE:
7989 case XML_DOCUMENT_TYPE_NODE:
7990 case XML_DOCUMENT_FRAG_NODE:
7991 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007992#ifdef LIBXML_DOCB_ENABLED
7993 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007994#endif
7995 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007996 case XML_NAMESPACE_DECL: {
7997 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007998
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007999 if ((ns->next != NULL) &&
8000 (ns->next->type != XML_NAMESPACE_DECL))
8001 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00008002 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008003 }
Owen Taylor3473f882001-02-23 17:55:21 +00008004 }
8005 }
8006 return(NULL);
8007}
8008
8009/**
8010 * xmlXPathNextAncestor:
8011 * @ctxt: the XPath Parser context
8012 * @cur: the current node in the traversal
8013 *
8014 * Traversal function for the "ancestor" direction
8015 * the ancestor axis contains the ancestors of the context node; the ancestors
8016 * of the context node consist of the parent of context node and the parent's
8017 * parent and so on; the nodes are ordered in reverse document order; thus the
8018 * parent is the first node on the axis, and the parent's parent is the second
8019 * node on the axis
8020 *
8021 * Returns the next element following that axis
8022 */
8023xmlNodePtr
8024xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008025 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008026 /*
8027 * the parent of an attribute or namespace node is the element
8028 * to which the attribute or namespace node is attached
8029 * !!!!!!!!!!!!!
8030 */
8031 if (cur == NULL) {
8032 if (ctxt->context->node == NULL) return(NULL);
8033 switch (ctxt->context->node->type) {
8034 case XML_ELEMENT_NODE:
8035 case XML_TEXT_NODE:
8036 case XML_CDATA_SECTION_NODE:
8037 case XML_ENTITY_REF_NODE:
8038 case XML_ENTITY_NODE:
8039 case XML_PI_NODE:
8040 case XML_COMMENT_NODE:
8041 case XML_DTD_NODE:
8042 case XML_ELEMENT_DECL:
8043 case XML_ATTRIBUTE_DECL:
8044 case XML_ENTITY_DECL:
8045 case XML_NOTATION_NODE:
8046 case XML_XINCLUDE_START:
8047 case XML_XINCLUDE_END:
8048 if (ctxt->context->node->parent == NULL)
8049 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008050 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008051 ((ctxt->context->node->parent->name[0] == ' ') ||
8052 (xmlStrEqual(ctxt->context->node->parent->name,
8053 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008054 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008055 return(ctxt->context->node->parent);
8056 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008057 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00008058
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008059 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00008060 }
8061 case XML_DOCUMENT_NODE:
8062 case XML_DOCUMENT_TYPE_NODE:
8063 case XML_DOCUMENT_FRAG_NODE:
8064 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008065#ifdef LIBXML_DOCB_ENABLED
8066 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008067#endif
8068 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008069 case XML_NAMESPACE_DECL: {
8070 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008071
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008072 if ((ns->next != NULL) &&
8073 (ns->next->type != XML_NAMESPACE_DECL))
8074 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008075 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008076 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008077 }
Owen Taylor3473f882001-02-23 17:55:21 +00008078 }
8079 return(NULL);
8080 }
8081 if (cur == ctxt->context->doc->children)
8082 return((xmlNodePtr) ctxt->context->doc);
8083 if (cur == (xmlNodePtr) ctxt->context->doc)
8084 return(NULL);
8085 switch (cur->type) {
8086 case XML_ELEMENT_NODE:
8087 case XML_TEXT_NODE:
8088 case XML_CDATA_SECTION_NODE:
8089 case XML_ENTITY_REF_NODE:
8090 case XML_ENTITY_NODE:
8091 case XML_PI_NODE:
8092 case XML_COMMENT_NODE:
8093 case XML_NOTATION_NODE:
8094 case XML_DTD_NODE:
8095 case XML_ELEMENT_DECL:
8096 case XML_ATTRIBUTE_DECL:
8097 case XML_ENTITY_DECL:
8098 case XML_XINCLUDE_START:
8099 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008100 if (cur->parent == NULL)
8101 return(NULL);
8102 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008103 ((cur->parent->name[0] == ' ') ||
8104 (xmlStrEqual(cur->parent->name,
8105 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008106 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008107 return(cur->parent);
8108 case XML_ATTRIBUTE_NODE: {
8109 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8110
8111 return(att->parent);
8112 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008113 case XML_NAMESPACE_DECL: {
8114 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008115
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008116 if ((ns->next != NULL) &&
8117 (ns->next->type != XML_NAMESPACE_DECL))
8118 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008119 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008120 return(NULL);
8121 }
Owen Taylor3473f882001-02-23 17:55:21 +00008122 case XML_DOCUMENT_NODE:
8123 case XML_DOCUMENT_TYPE_NODE:
8124 case XML_DOCUMENT_FRAG_NODE:
8125 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008126#ifdef LIBXML_DOCB_ENABLED
8127 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008128#endif
8129 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008130 }
8131 return(NULL);
8132}
8133
8134/**
8135 * xmlXPathNextAncestorOrSelf:
8136 * @ctxt: the XPath Parser context
8137 * @cur: the current node in the traversal
8138 *
8139 * Traversal function for the "ancestor-or-self" direction
8140 * he ancestor-or-self axis contains the context node and ancestors of
8141 * the context node in reverse document order; thus the context node is
8142 * the first node on the axis, and the context node's parent the second;
8143 * parent here is defined the same as with the parent axis.
8144 *
8145 * Returns the next element following that axis
8146 */
8147xmlNodePtr
8148xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008149 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008150 if (cur == NULL)
8151 return(ctxt->context->node);
8152 return(xmlXPathNextAncestor(ctxt, cur));
8153}
8154
8155/**
8156 * xmlXPathNextFollowingSibling:
8157 * @ctxt: the XPath Parser context
8158 * @cur: the current node in the traversal
8159 *
8160 * Traversal function for the "following-sibling" direction
8161 * The following-sibling axis contains the following siblings of the context
8162 * node in document order.
8163 *
8164 * Returns the next element following that axis
8165 */
8166xmlNodePtr
8167xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008168 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008169 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8170 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8171 return(NULL);
8172 if (cur == (xmlNodePtr) ctxt->context->doc)
8173 return(NULL);
8174 if (cur == NULL)
8175 return(ctxt->context->node->next);
8176 return(cur->next);
8177}
8178
8179/**
8180 * xmlXPathNextPrecedingSibling:
8181 * @ctxt: the XPath Parser context
8182 * @cur: the current node in the traversal
8183 *
8184 * Traversal function for the "preceding-sibling" direction
8185 * The preceding-sibling axis contains the preceding siblings of the context
8186 * node in reverse document order; the first preceding sibling is first on the
8187 * axis; the sibling preceding that node is the second on the axis and so on.
8188 *
8189 * Returns the next element following that axis
8190 */
8191xmlNodePtr
8192xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008193 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008194 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8195 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8196 return(NULL);
8197 if (cur == (xmlNodePtr) ctxt->context->doc)
8198 return(NULL);
8199 if (cur == NULL)
8200 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008201 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8202 cur = cur->prev;
8203 if (cur == NULL)
8204 return(ctxt->context->node->prev);
8205 }
Owen Taylor3473f882001-02-23 17:55:21 +00008206 return(cur->prev);
8207}
8208
8209/**
8210 * xmlXPathNextFollowing:
8211 * @ctxt: the XPath Parser context
8212 * @cur: the current node in the traversal
8213 *
8214 * Traversal function for the "following" direction
8215 * The following axis contains all nodes in the same document as the context
8216 * node that are after the context node in document order, excluding any
8217 * descendants and excluding attribute nodes and namespace nodes; the nodes
8218 * are ordered in document order
8219 *
8220 * Returns the next element following that axis
8221 */
8222xmlNodePtr
8223xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008224 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008225 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8226 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8227 return(cur->children);
8228
8229 if (cur == NULL) {
8230 cur = ctxt->context->node;
8231 if (cur->type == XML_NAMESPACE_DECL)
Daniel Veillard91d19752010-10-15 14:30:52 +02008232 return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008233 if (cur->type == XML_ATTRIBUTE_NODE)
8234 cur = cur->parent;
Daniel Veillard91d19752010-10-15 14:30:52 +02008235 }
Owen Taylor3473f882001-02-23 17:55:21 +00008236 if (cur == NULL) return(NULL) ; /* ERROR */
8237 if (cur->next != NULL) return(cur->next) ;
8238 do {
8239 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008240 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008241 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8242 if (cur->next != NULL) return(cur->next);
8243 } while (cur != NULL);
8244 return(cur);
8245}
8246
8247/*
8248 * xmlXPathIsAncestor:
8249 * @ancestor: the ancestor node
8250 * @node: the current node
8251 *
8252 * Check that @ancestor is a @node's ancestor
8253 *
8254 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8255 */
8256static int
8257xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8258 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008259 if (node->type == XML_NAMESPACE_DECL)
8260 return(0);
8261 if (ancestor->type == XML_NAMESPACE_DECL)
8262 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008263 /* nodes need to be in the same document */
8264 if (ancestor->doc != node->doc) return(0);
8265 /* avoid searching if ancestor or node is the root node */
8266 if (ancestor == (xmlNodePtr) node->doc) return(1);
8267 if (node == (xmlNodePtr) ancestor->doc) return(0);
8268 while (node->parent != NULL) {
8269 if (node->parent == ancestor)
8270 return(1);
8271 node = node->parent;
8272 }
8273 return(0);
8274}
8275
8276/**
8277 * xmlXPathNextPreceding:
8278 * @ctxt: the XPath Parser context
8279 * @cur: the current node in the traversal
8280 *
8281 * Traversal function for the "preceding" direction
8282 * the preceding axis contains all nodes in the same document as the context
8283 * node that are before the context node in document order, excluding any
8284 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8285 * ordered in reverse document order
8286 *
8287 * Returns the next element following that axis
8288 */
8289xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008290xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8291{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008292 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008293 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008294 cur = ctxt->context->node;
Daniel Veillardea90b892010-10-22 15:50:50 +02008295 if (cur->type == XML_NAMESPACE_DECL)
8296 return(NULL);
8297 if (cur->type == XML_ATTRIBUTE_NODE)
8298 return(cur->parent);
8299 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008300 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008301 return (NULL);
8302 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8303 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008304 do {
8305 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008306 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8307 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008308 }
8309
8310 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008311 if (cur == NULL)
8312 return (NULL);
8313 if (cur == ctxt->context->doc->children)
8314 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008315 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008316 return (cur);
8317}
8318
8319/**
8320 * xmlXPathNextPrecedingInternal:
8321 * @ctxt: the XPath Parser context
8322 * @cur: the current node in the traversal
8323 *
8324 * Traversal function for the "preceding" direction
8325 * the preceding axis contains all nodes in the same document as the context
8326 * node that are before the context node in document order, excluding any
8327 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8328 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008329 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008330 * state kept in the parser context: ctxt->ancestor.
8331 *
8332 * Returns the next element following that axis
8333 */
8334static xmlNodePtr
8335xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8336 xmlNodePtr cur)
8337{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008338 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008339 if (cur == NULL) {
8340 cur = ctxt->context->node;
8341 if (cur == NULL)
8342 return (NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008343 if (cur->type == XML_NAMESPACE_DECL)
8344 return (NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008345 ctxt->ancestor = cur->parent;
8346 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008347 if (cur->type == XML_NAMESPACE_DECL)
8348 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008349 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8350 cur = cur->prev;
8351 while (cur->prev == NULL) {
8352 cur = cur->parent;
8353 if (cur == NULL)
8354 return (NULL);
8355 if (cur == ctxt->context->doc->children)
8356 return (NULL);
8357 if (cur != ctxt->ancestor)
8358 return (cur);
8359 ctxt->ancestor = cur->parent;
8360 }
8361 cur = cur->prev;
8362 while (cur->last != NULL)
8363 cur = cur->last;
8364 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008365}
8366
8367/**
8368 * xmlXPathNextNamespace:
8369 * @ctxt: the XPath Parser context
8370 * @cur: the current attribute in the traversal
8371 *
8372 * Traversal function for the "namespace" direction
8373 * the namespace axis contains the namespace nodes of the context node;
8374 * the order of nodes on this axis is implementation-defined; the axis will
8375 * be empty unless the context node is an element
8376 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008377 * We keep the XML namespace node at the end of the list.
8378 *
Owen Taylor3473f882001-02-23 17:55:21 +00008379 * Returns the next element following that axis
8380 */
8381xmlNodePtr
8382xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008383 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008384 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008385 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008386 if (ctxt->context->tmpNsList != NULL)
8387 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008388 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008389 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008390 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008391 if (ctxt->context->tmpNsList != NULL) {
8392 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8393 ctxt->context->tmpNsNr++;
8394 }
8395 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008396 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008397 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008398 if (ctxt->context->tmpNsNr > 0) {
8399 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8400 } else {
8401 if (ctxt->context->tmpNsList != NULL)
8402 xmlFree(ctxt->context->tmpNsList);
8403 ctxt->context->tmpNsList = NULL;
8404 return(NULL);
8405 }
Owen Taylor3473f882001-02-23 17:55:21 +00008406}
8407
8408/**
8409 * xmlXPathNextAttribute:
8410 * @ctxt: the XPath Parser context
8411 * @cur: the current attribute in the traversal
8412 *
8413 * Traversal function for the "attribute" direction
8414 * TODO: support DTD inherited default attributes
8415 *
8416 * Returns the next element following that axis
8417 */
8418xmlNodePtr
8419xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008420 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008421 if (ctxt->context->node == NULL)
8422 return(NULL);
8423 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8424 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008425 if (cur == NULL) {
8426 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8427 return(NULL);
8428 return((xmlNodePtr)ctxt->context->node->properties);
8429 }
8430 return((xmlNodePtr)cur->next);
8431}
8432
8433/************************************************************************
8434 * *
8435 * NodeTest Functions *
8436 * *
8437 ************************************************************************/
8438
Owen Taylor3473f882001-02-23 17:55:21 +00008439#define IS_FUNCTION 200
8440
Owen Taylor3473f882001-02-23 17:55:21 +00008441
8442/************************************************************************
8443 * *
8444 * Implicit tree core function library *
8445 * *
8446 ************************************************************************/
8447
8448/**
8449 * xmlXPathRoot:
8450 * @ctxt: the XPath Parser context
8451 *
8452 * Initialize the context to the root of the document
8453 */
8454void
8455xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008456 if ((ctxt == NULL) || (ctxt->context == NULL))
8457 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008458 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008459 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8460 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008461}
8462
8463/************************************************************************
8464 * *
8465 * The explicit core function library *
8466 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8467 * *
8468 ************************************************************************/
8469
8470
8471/**
8472 * xmlXPathLastFunction:
8473 * @ctxt: the XPath Parser context
8474 * @nargs: the number of arguments
8475 *
8476 * Implement the last() XPath function
8477 * number last()
8478 * The last function returns the number of nodes in the context node list.
8479 */
8480void
8481xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8482 CHECK_ARITY(0);
8483 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008484 valuePush(ctxt,
8485 xmlXPathCacheNewFloat(ctxt->context,
8486 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008487#ifdef DEBUG_EXPR
8488 xmlGenericError(xmlGenericErrorContext,
8489 "last() : %d\n", ctxt->context->contextSize);
8490#endif
8491 } else {
8492 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8493 }
8494}
8495
8496/**
8497 * xmlXPathPositionFunction:
8498 * @ctxt: the XPath Parser context
8499 * @nargs: the number of arguments
8500 *
8501 * Implement the position() XPath function
8502 * number position()
8503 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008504 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008505 * will be equal to last().
8506 */
8507void
8508xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8509 CHECK_ARITY(0);
8510 if (ctxt->context->proximityPosition >= 0) {
8511 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008512 xmlXPathCacheNewFloat(ctxt->context,
8513 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008514#ifdef DEBUG_EXPR
8515 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8516 ctxt->context->proximityPosition);
8517#endif
8518 } else {
8519 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8520 }
8521}
8522
8523/**
8524 * xmlXPathCountFunction:
8525 * @ctxt: the XPath Parser context
8526 * @nargs: the number of arguments
8527 *
8528 * Implement the count() XPath function
8529 * number count(node-set)
8530 */
8531void
8532xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8533 xmlXPathObjectPtr cur;
8534
8535 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008536 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008537 ((ctxt->value->type != XPATH_NODESET) &&
8538 (ctxt->value->type != XPATH_XSLT_TREE)))
8539 XP_ERROR(XPATH_INVALID_TYPE);
8540 cur = valuePop(ctxt);
8541
Daniel Veillard911f49a2001-04-07 15:39:35 +00008542 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008543 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008544 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008545 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8546 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008547 } else {
8548 if ((cur->nodesetval->nodeNr != 1) ||
8549 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008550 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008551 } else {
8552 xmlNodePtr tmp;
8553 int i = 0;
8554
8555 tmp = cur->nodesetval->nodeTab[0];
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008556 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
Daniel Veillardfe703322001-08-14 12:18:09 +00008557 tmp = tmp->children;
8558 while (tmp != NULL) {
8559 tmp = tmp->next;
8560 i++;
8561 }
8562 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008563 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008564 }
8565 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008566 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008567}
8568
8569/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008570 * xmlXPathGetElementsByIds:
8571 * @doc: the document
8572 * @ids: a whitespace separated list of IDs
8573 *
8574 * Selects elements by their unique ID.
8575 *
8576 * Returns a node-set of selected elements.
8577 */
8578static xmlNodeSetPtr
8579xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8580 xmlNodeSetPtr ret;
8581 const xmlChar *cur = ids;
8582 xmlChar *ID;
8583 xmlAttrPtr attr;
8584 xmlNodePtr elem = NULL;
8585
Daniel Veillard7a985a12003-07-06 17:57:42 +00008586 if (ids == NULL) return(NULL);
8587
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008588 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008589 if (ret == NULL)
8590 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008591
William M. Brack76e95df2003-10-18 16:20:14 +00008592 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008593 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008594 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008595 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008596
8597 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008598 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008599 /*
8600 * We used to check the fact that the value passed
8601 * was an NCName, but this generated much troubles for
8602 * me and Aleksey Sanin, people blatantly violated that
8603 * constaint, like Visa3D spec.
8604 * if (xmlValidateNCName(ID, 1) == 0)
8605 */
8606 attr = xmlGetID(doc, ID);
8607 if (attr != NULL) {
8608 if (attr->type == XML_ATTRIBUTE_NODE)
8609 elem = attr->parent;
8610 else if (attr->type == XML_ELEMENT_NODE)
8611 elem = (xmlNodePtr) attr;
8612 else
8613 elem = NULL;
8614 if (elem != NULL)
8615 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008616 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008617 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008618 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008619
William M. Brack76e95df2003-10-18 16:20:14 +00008620 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008621 ids = cur;
8622 }
8623 return(ret);
8624}
8625
8626/**
Owen Taylor3473f882001-02-23 17:55:21 +00008627 * xmlXPathIdFunction:
8628 * @ctxt: the XPath Parser context
8629 * @nargs: the number of arguments
8630 *
8631 * Implement the id() XPath function
8632 * node-set id(object)
8633 * The id function selects elements by their unique ID
8634 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8635 * then the result is the union of the result of applying id to the
8636 * string value of each of the nodes in the argument node-set. When the
8637 * argument to id is of any other type, the argument is converted to a
8638 * string as if by a call to the string function; the string is split
8639 * into a whitespace-separated list of tokens (whitespace is any sequence
8640 * of characters matching the production S); the result is a node-set
8641 * containing the elements in the same document as the context node that
8642 * have a unique ID equal to any of the tokens in the list.
8643 */
8644void
8645xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008646 xmlChar *tokens;
8647 xmlNodeSetPtr ret;
8648 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008649
8650 CHECK_ARITY(1);
8651 obj = valuePop(ctxt);
8652 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008653 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008654 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008655 int i;
8656
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008657 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008658 /*
8659 * FIXME -- in an out-of-memory condition this will behave badly.
8660 * The solution is not clear -- we already popped an item from
8661 * ctxt, so the object is in a corrupt state.
8662 */
Owen Taylor3473f882001-02-23 17:55:21 +00008663
Daniel Veillard911f49a2001-04-07 15:39:35 +00008664 if (obj->nodesetval != NULL) {
8665 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008666 tokens =
8667 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8668 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8669 ret = xmlXPathNodeSetMerge(ret, ns);
8670 xmlXPathFreeNodeSet(ns);
8671 if (tokens != NULL)
8672 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008673 }
Owen Taylor3473f882001-02-23 17:55:21 +00008674 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008675 xmlXPathReleaseObject(ctxt->context, obj);
8676 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008677 return;
8678 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008679 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008680 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008681 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008682 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008683 return;
8684}
8685
8686/**
8687 * xmlXPathLocalNameFunction:
8688 * @ctxt: the XPath Parser context
8689 * @nargs: the number of arguments
8690 *
8691 * Implement the local-name() XPath function
8692 * string local-name(node-set?)
8693 * The local-name function returns a string containing the local part
8694 * of the name of the node in the argument node-set that is first in
8695 * document order. If the node-set is empty or the first node has no
8696 * name, an empty string is returned. If the argument is omitted it
8697 * defaults to the context node.
8698 */
8699void
8700xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8701 xmlXPathObjectPtr cur;
8702
Daniel Veillarda82b1822004-11-08 16:24:57 +00008703 if (ctxt == NULL) return;
8704
Owen Taylor3473f882001-02-23 17:55:21 +00008705 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008706 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8707 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008708 nargs = 1;
8709 }
8710
8711 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008712 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008713 ((ctxt->value->type != XPATH_NODESET) &&
8714 (ctxt->value->type != XPATH_XSLT_TREE)))
8715 XP_ERROR(XPATH_INVALID_TYPE);
8716 cur = valuePop(ctxt);
8717
Daniel Veillard911f49a2001-04-07 15:39:35 +00008718 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008719 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008720 } else {
8721 int i = 0; /* Should be first in document order !!!!! */
8722 switch (cur->nodesetval->nodeTab[i]->type) {
8723 case XML_ELEMENT_NODE:
8724 case XML_ATTRIBUTE_NODE:
8725 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008726 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008727 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008728 else
8729 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008730 xmlXPathCacheNewString(ctxt->context,
8731 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008732 break;
8733 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008734 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008735 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8736 break;
8737 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008738 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008739 }
8740 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008741 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008742}
8743
8744/**
8745 * xmlXPathNamespaceURIFunction:
8746 * @ctxt: the XPath Parser context
8747 * @nargs: the number of arguments
8748 *
8749 * Implement the namespace-uri() XPath function
8750 * string namespace-uri(node-set?)
8751 * The namespace-uri function returns a string containing the
8752 * namespace URI of the expanded name of the node in the argument
8753 * node-set that is first in document order. If the node-set is empty,
8754 * the first node has no name, or the expanded name has no namespace
8755 * URI, an empty string is returned. If the argument is omitted it
8756 * defaults to the context node.
8757 */
8758void
8759xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8760 xmlXPathObjectPtr cur;
8761
Daniel Veillarda82b1822004-11-08 16:24:57 +00008762 if (ctxt == NULL) return;
8763
Owen Taylor3473f882001-02-23 17:55:21 +00008764 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008765 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8766 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008767 nargs = 1;
8768 }
8769 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008770 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008771 ((ctxt->value->type != XPATH_NODESET) &&
8772 (ctxt->value->type != XPATH_XSLT_TREE)))
8773 XP_ERROR(XPATH_INVALID_TYPE);
8774 cur = valuePop(ctxt);
8775
Daniel Veillard911f49a2001-04-07 15:39:35 +00008776 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008777 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008778 } else {
8779 int i = 0; /* Should be first in document order !!!!! */
8780 switch (cur->nodesetval->nodeTab[i]->type) {
8781 case XML_ELEMENT_NODE:
8782 case XML_ATTRIBUTE_NODE:
8783 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008784 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008785 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008786 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008787 cur->nodesetval->nodeTab[i]->ns->href));
8788 break;
8789 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008790 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008791 }
8792 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008793 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008794}
8795
8796/**
8797 * xmlXPathNameFunction:
8798 * @ctxt: the XPath Parser context
8799 * @nargs: the number of arguments
8800 *
8801 * Implement the name() XPath function
8802 * string name(node-set?)
8803 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008804 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008805 * order. The QName must represent the name with respect to the namespace
8806 * declarations in effect on the node whose name is being represented.
8807 * Typically, this will be the form in which the name occurred in the XML
8808 * source. This need not be the case if there are namespace declarations
8809 * in effect on the node that associate multiple prefixes with the same
8810 * namespace. However, an implementation may include information about
8811 * the original prefix in its representation of nodes; in this case, an
8812 * implementation can ensure that the returned string is always the same
8813 * as the QName used in the XML source. If the argument it omitted it
8814 * defaults to the context node.
8815 * Libxml keep the original prefix so the "real qualified name" used is
8816 * returned.
8817 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008818static void
Daniel Veillard04383752001-07-08 14:27:15 +00008819xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8820{
Owen Taylor3473f882001-02-23 17:55:21 +00008821 xmlXPathObjectPtr cur;
8822
8823 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008824 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8825 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008826 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008827 }
8828
8829 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008830 if ((ctxt->value == NULL) ||
8831 ((ctxt->value->type != XPATH_NODESET) &&
8832 (ctxt->value->type != XPATH_XSLT_TREE)))
8833 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008834 cur = valuePop(ctxt);
8835
Daniel Veillard911f49a2001-04-07 15:39:35 +00008836 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008837 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008838 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008839 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008840
Daniel Veillard04383752001-07-08 14:27:15 +00008841 switch (cur->nodesetval->nodeTab[i]->type) {
8842 case XML_ELEMENT_NODE:
8843 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008844 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008845 valuePush(ctxt,
8846 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008847 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8848 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008849 valuePush(ctxt,
8850 xmlXPathCacheNewString(ctxt->context,
8851 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008852 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008853 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008854
Daniel Veillardc00cda82003-04-07 10:22:39 +00008855 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8856 cur->nodesetval->nodeTab[i]->ns->prefix,
8857 NULL, 0);
8858 if (fullname == cur->nodesetval->nodeTab[i]->name)
8859 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8860 if (fullname == NULL) {
8861 XP_ERROR(XPATH_MEMORY_ERROR);
8862 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008863 valuePush(ctxt, xmlXPathCacheWrapString(
8864 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008865 }
8866 break;
8867 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008868 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8869 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008870 xmlXPathLocalNameFunction(ctxt, 1);
8871 }
Owen Taylor3473f882001-02-23 17:55:21 +00008872 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008873 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008874}
8875
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008876
8877/**
Owen Taylor3473f882001-02-23 17:55:21 +00008878 * xmlXPathStringFunction:
8879 * @ctxt: the XPath Parser context
8880 * @nargs: the number of arguments
8881 *
8882 * Implement the string() XPath function
8883 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008884 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008885 * - A node-set is converted to a string by returning the value of
8886 * the node in the node-set that is first in document order.
8887 * If the node-set is empty, an empty string is returned.
8888 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008889 * + NaN is converted to the string NaN
8890 * + positive zero is converted to the string 0
8891 * + negative zero is converted to the string 0
8892 * + positive infinity is converted to the string Infinity
8893 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008894 * + if the number is an integer, the number is represented in
8895 * decimal form as a Number with no decimal point and no leading
8896 * zeros, preceded by a minus sign (-) if the number is negative
8897 * + otherwise, the number is represented in decimal form as a
8898 * Number including a decimal point with at least one digit
8899 * before the decimal point and at least one digit after the
8900 * decimal point, preceded by a minus sign (-) if the number
8901 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008902 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008903 * before the decimal point; beyond the one required digit
8904 * after the decimal point there must be as many, but only as
8905 * many, more digits as are needed to uniquely distinguish the
8906 * number from all other IEEE 754 numeric values.
8907 * - The boolean false value is converted to the string false.
8908 * The boolean true value is converted to the string true.
8909 *
8910 * If the argument is omitted, it defaults to a node-set with the
8911 * context node as its only member.
8912 */
8913void
8914xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8915 xmlXPathObjectPtr cur;
8916
Daniel Veillarda82b1822004-11-08 16:24:57 +00008917 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008918 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008919 valuePush(ctxt,
8920 xmlXPathCacheWrapString(ctxt->context,
8921 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008922 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008923 }
8924
8925 CHECK_ARITY(1);
8926 cur = valuePop(ctxt);
8927 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008928 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008929}
8930
8931/**
8932 * xmlXPathStringLengthFunction:
8933 * @ctxt: the XPath Parser context
8934 * @nargs: the number of arguments
8935 *
8936 * Implement the string-length() XPath function
8937 * number string-length(string?)
8938 * The string-length returns the number of characters in the string
8939 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8940 * the context node converted to a string, in other words the value
8941 * of the context node.
8942 */
8943void
8944xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8945 xmlXPathObjectPtr cur;
8946
8947 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008948 if ((ctxt == NULL) || (ctxt->context == NULL))
8949 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008950 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008951 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008952 } else {
8953 xmlChar *content;
8954
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008955 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008956 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8957 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008958 xmlFree(content);
8959 }
8960 return;
8961 }
8962 CHECK_ARITY(1);
8963 CAST_TO_STRING;
8964 CHECK_TYPE(XPATH_STRING);
8965 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008966 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008967 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008968 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008969}
8970
8971/**
8972 * xmlXPathConcatFunction:
8973 * @ctxt: the XPath Parser context
8974 * @nargs: the number of arguments
8975 *
8976 * Implement the concat() XPath function
8977 * string concat(string, string, string*)
8978 * The concat function returns the concatenation of its arguments.
8979 */
8980void
8981xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8982 xmlXPathObjectPtr cur, newobj;
8983 xmlChar *tmp;
8984
Daniel Veillarda82b1822004-11-08 16:24:57 +00008985 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008986 if (nargs < 2) {
8987 CHECK_ARITY(2);
8988 }
8989
8990 CAST_TO_STRING;
8991 cur = valuePop(ctxt);
8992 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008993 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008994 return;
8995 }
8996 nargs--;
8997
8998 while (nargs > 0) {
8999 CAST_TO_STRING;
9000 newobj = valuePop(ctxt);
9001 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009002 xmlXPathReleaseObject(ctxt->context, newobj);
9003 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009004 XP_ERROR(XPATH_INVALID_TYPE);
9005 }
9006 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9007 newobj->stringval = cur->stringval;
9008 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009009 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00009010 nargs--;
9011 }
9012 valuePush(ctxt, cur);
9013}
9014
9015/**
9016 * xmlXPathContainsFunction:
9017 * @ctxt: the XPath Parser context
9018 * @nargs: the number of arguments
9019 *
9020 * Implement the contains() XPath function
9021 * boolean contains(string, string)
9022 * The contains function returns true if the first argument string
9023 * contains the second argument string, and otherwise returns false.
9024 */
9025void
9026xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9027 xmlXPathObjectPtr hay, needle;
9028
9029 CHECK_ARITY(2);
9030 CAST_TO_STRING;
9031 CHECK_TYPE(XPATH_STRING);
9032 needle = valuePop(ctxt);
9033 CAST_TO_STRING;
9034 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009035
Owen Taylor3473f882001-02-23 17:55:21 +00009036 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009037 xmlXPathReleaseObject(ctxt->context, hay);
9038 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009039 XP_ERROR(XPATH_INVALID_TYPE);
9040 }
9041 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009042 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009043 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009044 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9045 xmlXPathReleaseObject(ctxt->context, hay);
9046 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009047}
9048
9049/**
9050 * xmlXPathStartsWithFunction:
9051 * @ctxt: the XPath Parser context
9052 * @nargs: the number of arguments
9053 *
9054 * Implement the starts-with() XPath function
9055 * boolean starts-with(string, string)
9056 * The starts-with function returns true if the first argument string
9057 * starts with the second argument string, and otherwise returns false.
9058 */
9059void
9060xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9061 xmlXPathObjectPtr hay, needle;
9062 int n;
9063
9064 CHECK_ARITY(2);
9065 CAST_TO_STRING;
9066 CHECK_TYPE(XPATH_STRING);
9067 needle = valuePop(ctxt);
9068 CAST_TO_STRING;
9069 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009070
Owen Taylor3473f882001-02-23 17:55:21 +00009071 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009072 xmlXPathReleaseObject(ctxt->context, hay);
9073 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009074 XP_ERROR(XPATH_INVALID_TYPE);
9075 }
9076 n = xmlStrlen(needle->stringval);
9077 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009078 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009079 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009080 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9081 xmlXPathReleaseObject(ctxt->context, hay);
9082 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009083}
9084
9085/**
9086 * xmlXPathSubstringFunction:
9087 * @ctxt: the XPath Parser context
9088 * @nargs: the number of arguments
9089 *
9090 * Implement the substring() XPath function
9091 * string substring(string, number, number?)
9092 * The substring function returns the substring of the first argument
9093 * starting at the position specified in the second argument with
9094 * length specified in the third argument. For example,
9095 * substring("12345",2,3) returns "234". If the third argument is not
9096 * specified, it returns the substring starting at the position specified
9097 * in the second argument and continuing to the end of the string. For
9098 * example, substring("12345",2) returns "2345". More precisely, each
9099 * character in the string (see [3.6 Strings]) is considered to have a
9100 * numeric position: the position of the first character is 1, the position
9101 * of the second character is 2 and so on. The returned substring contains
9102 * those characters for which the position of the character is greater than
9103 * or equal to the second argument and, if the third argument is specified,
9104 * less than the sum of the second and third arguments; the comparisons
9105 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009106 * - substring("12345", 1.5, 2.6) returns "234"
9107 * - substring("12345", 0, 3) returns "12"
9108 * - substring("12345", 0 div 0, 3) returns ""
9109 * - substring("12345", 1, 0 div 0) returns ""
9110 * - substring("12345", -42, 1 div 0) returns "12345"
9111 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009112 */
9113void
9114xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9115 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009116 double le=0, in;
9117 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009118 xmlChar *ret;
9119
Owen Taylor3473f882001-02-23 17:55:21 +00009120 if (nargs < 2) {
9121 CHECK_ARITY(2);
9122 }
9123 if (nargs > 3) {
9124 CHECK_ARITY(3);
9125 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009126 /*
9127 * take care of possible last (position) argument
9128 */
Owen Taylor3473f882001-02-23 17:55:21 +00009129 if (nargs == 3) {
9130 CAST_TO_NUMBER;
9131 CHECK_TYPE(XPATH_NUMBER);
9132 len = valuePop(ctxt);
9133 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009134 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009135 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009136
Owen Taylor3473f882001-02-23 17:55:21 +00009137 CAST_TO_NUMBER;
9138 CHECK_TYPE(XPATH_NUMBER);
9139 start = valuePop(ctxt);
9140 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009141 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009142 CAST_TO_STRING;
9143 CHECK_TYPE(XPATH_STRING);
9144 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009145 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009146
Daniel Veillard97ac1312001-05-30 19:14:17 +00009147 /*
9148 * If last pos not present, calculate last position
9149 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009150 if (nargs != 3) {
9151 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009152 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009153 in = 1.0;
9154 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009155
Daniel Veillard45490ae2008-07-29 09:13:19 +00009156 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009157 * the index is NaN, the length is NaN, or both
9158 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009159 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009160 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009161 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009162 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009163 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009164 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009165 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009166 * First we go to integer form, rounding up
9167 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009168 */
9169 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009170 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009171
Daniel Veillard9e412302002-06-10 15:59:44 +00009172 if (xmlXPathIsInf(le) == 1) {
9173 l = m;
9174 if (i < 1)
9175 i = 1;
9176 }
9177 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9178 l = 0;
9179 else {
9180 l = (int) le;
9181 if (((double)l)+0.5 <= le) l++;
9182 }
9183
9184 /* Now we normalize inidices */
9185 i -= 1;
9186 l += i;
9187 if (i < 0)
9188 i = 0;
9189 if (l > m)
9190 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009191
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009192 /* number of chars to copy */
9193 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009194
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009195 ret = xmlUTF8Strsub(str->stringval, i, l);
9196 }
9197 else {
9198 ret = NULL;
9199 }
Owen Taylor3473f882001-02-23 17:55:21 +00009200 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009201 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009202 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009203 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009204 xmlFree(ret);
9205 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009206 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009207}
9208
9209/**
9210 * xmlXPathSubstringBeforeFunction:
9211 * @ctxt: the XPath Parser context
9212 * @nargs: the number of arguments
9213 *
9214 * Implement the substring-before() XPath function
9215 * string substring-before(string, string)
9216 * The substring-before function returns the substring of the first
9217 * argument string that precedes the first occurrence of the second
9218 * argument string in the first argument string, or the empty string
9219 * if the first argument string does not contain the second argument
9220 * string. For example, substring-before("1999/04/01","/") returns 1999.
9221 */
9222void
9223xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9224 xmlXPathObjectPtr str;
9225 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009226 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009227 const xmlChar *point;
9228 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009229
Owen Taylor3473f882001-02-23 17:55:21 +00009230 CHECK_ARITY(2);
9231 CAST_TO_STRING;
9232 find = valuePop(ctxt);
9233 CAST_TO_STRING;
9234 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009235
Daniel Veillardade10f22012-07-12 09:43:27 +08009236 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009237 if (target) {
9238 point = xmlStrstr(str->stringval, find->stringval);
9239 if (point) {
9240 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009241 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009242 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009243 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009244 xmlBufContent(target)));
9245 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009246 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009247 xmlXPathReleaseObject(ctxt->context, str);
9248 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009249}
9250
9251/**
9252 * xmlXPathSubstringAfterFunction:
9253 * @ctxt: the XPath Parser context
9254 * @nargs: the number of arguments
9255 *
9256 * Implement the substring-after() XPath function
9257 * string substring-after(string, string)
9258 * The substring-after function returns the substring of the first
9259 * argument string that follows the first occurrence of the second
9260 * argument string in the first argument string, or the empty stringi
9261 * if the first argument string does not contain the second argument
9262 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9263 * and substring-after("1999/04/01","19") returns 99/04/01.
9264 */
9265void
9266xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9267 xmlXPathObjectPtr str;
9268 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009269 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009270 const xmlChar *point;
9271 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009272
Owen Taylor3473f882001-02-23 17:55:21 +00009273 CHECK_ARITY(2);
9274 CAST_TO_STRING;
9275 find = valuePop(ctxt);
9276 CAST_TO_STRING;
9277 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009278
Daniel Veillardade10f22012-07-12 09:43:27 +08009279 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009280 if (target) {
9281 point = xmlStrstr(str->stringval, find->stringval);
9282 if (point) {
9283 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009284 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009285 xmlStrlen(str->stringval) - offset);
9286 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009287 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009288 xmlBufContent(target)));
9289 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009290 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009291 xmlXPathReleaseObject(ctxt->context, str);
9292 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009293}
9294
9295/**
9296 * xmlXPathNormalizeFunction:
9297 * @ctxt: the XPath Parser context
9298 * @nargs: the number of arguments
9299 *
9300 * Implement the normalize-space() XPath function
9301 * string normalize-space(string?)
9302 * The normalize-space function returns the argument string with white
9303 * space normalized by stripping leading and trailing whitespace
9304 * and replacing sequences of whitespace characters by a single
9305 * space. Whitespace characters are the same allowed by the S production
9306 * in XML. If the argument is omitted, it defaults to the context
9307 * node converted to a string, in other words the value of the context node.
9308 */
9309void
9310xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9311 xmlXPathObjectPtr obj = NULL;
9312 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009313 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009314 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009315
Daniel Veillarda82b1822004-11-08 16:24:57 +00009316 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009317 if (nargs == 0) {
9318 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009319 valuePush(ctxt,
9320 xmlXPathCacheWrapString(ctxt->context,
9321 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009322 nargs = 1;
9323 }
9324
9325 CHECK_ARITY(1);
9326 CAST_TO_STRING;
9327 CHECK_TYPE(XPATH_STRING);
9328 obj = valuePop(ctxt);
9329 source = obj->stringval;
9330
Daniel Veillardade10f22012-07-12 09:43:27 +08009331 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009332 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009333
Owen Taylor3473f882001-02-23 17:55:21 +00009334 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009335 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009336 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009337
Owen Taylor3473f882001-02-23 17:55:21 +00009338 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9339 blank = 0;
9340 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009341 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009342 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009343 } else {
9344 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009345 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009346 blank = 0;
9347 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009348 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009349 }
9350 source++;
9351 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009352 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009353 xmlBufContent(target)));
9354 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009355 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009356 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009357}
9358
9359/**
9360 * xmlXPathTranslateFunction:
9361 * @ctxt: the XPath Parser context
9362 * @nargs: the number of arguments
9363 *
9364 * Implement the translate() XPath function
9365 * string translate(string, string, string)
9366 * The translate function returns the first argument string with
9367 * occurrences of characters in the second argument string replaced
9368 * by the character at the corresponding position in the third argument
9369 * string. For example, translate("bar","abc","ABC") returns the string
9370 * BAr. If there is a character in the second argument string with no
9371 * character at a corresponding position in the third argument string
9372 * (because the second argument string is longer than the third argument
9373 * string), then occurrences of that character in the first argument
9374 * string are removed. For example, translate("--aaa--","abc-","ABC")
9375 * returns "AAA". If a character occurs more than once in second
9376 * argument string, then the first occurrence determines the replacement
9377 * character. If the third argument string is longer than the second
9378 * argument string, then excess characters are ignored.
9379 */
9380void
9381xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009382 xmlXPathObjectPtr str;
9383 xmlXPathObjectPtr from;
9384 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009385 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009386 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009387 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009388 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009389 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009390
Daniel Veillarde043ee12001-04-16 14:08:07 +00009391 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009392
Daniel Veillarde043ee12001-04-16 14:08:07 +00009393 CAST_TO_STRING;
9394 to = valuePop(ctxt);
9395 CAST_TO_STRING;
9396 from = valuePop(ctxt);
9397 CAST_TO_STRING;
9398 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009399
Daniel Veillardade10f22012-07-12 09:43:27 +08009400 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009401 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009402 max = xmlUTF8Strlen(to->stringval);
9403 for (cptr = str->stringval; (ch=*cptr); ) {
9404 offset = xmlUTF8Strloc(from->stringval, cptr);
9405 if (offset >= 0) {
9406 if (offset < max) {
9407 point = xmlUTF8Strpos(to->stringval, offset);
9408 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009409 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009410 }
9411 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009412 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009413
9414 /* Step to next character in input */
9415 cptr++;
9416 if ( ch & 0x80 ) {
9417 /* if not simple ascii, verify proper format */
9418 if ( (ch & 0xc0) != 0xc0 ) {
9419 xmlGenericError(xmlGenericErrorContext,
9420 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009421 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009422 break;
9423 }
9424 /* then skip over remaining bytes for this char */
9425 while ( (ch <<= 1) & 0x80 )
9426 if ( (*cptr++ & 0xc0) != 0x80 ) {
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 if (ch & 0x80) /* must have had error encountered */
9433 break;
9434 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009435 }
Owen Taylor3473f882001-02-23 17:55:21 +00009436 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009437 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009438 xmlBufContent(target)));
9439 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009440 xmlXPathReleaseObject(ctxt->context, str);
9441 xmlXPathReleaseObject(ctxt->context, from);
9442 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009443}
9444
9445/**
9446 * xmlXPathBooleanFunction:
9447 * @ctxt: the XPath Parser context
9448 * @nargs: the number of arguments
9449 *
9450 * Implement the boolean() XPath function
9451 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009452 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009453 * - a number is true if and only if it is neither positive or
9454 * negative zero nor NaN
9455 * - a node-set is true if and only if it is non-empty
9456 * - a string is true if and only if its length is non-zero
9457 */
9458void
9459xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9460 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009461
9462 CHECK_ARITY(1);
9463 cur = valuePop(ctxt);
9464 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009465 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009466 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009467}
9468
9469/**
9470 * xmlXPathNotFunction:
9471 * @ctxt: the XPath Parser context
9472 * @nargs: the number of arguments
9473 *
9474 * Implement the not() XPath function
9475 * boolean not(boolean)
9476 * The not function returns true if its argument is false,
9477 * and false otherwise.
9478 */
9479void
9480xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9481 CHECK_ARITY(1);
9482 CAST_TO_BOOLEAN;
9483 CHECK_TYPE(XPATH_BOOLEAN);
9484 ctxt->value->boolval = ! ctxt->value->boolval;
9485}
9486
9487/**
9488 * xmlXPathTrueFunction:
9489 * @ctxt: the XPath Parser context
9490 * @nargs: the number of arguments
9491 *
9492 * Implement the true() XPath function
9493 * boolean true()
9494 */
9495void
9496xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9497 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009498 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009499}
9500
9501/**
9502 * xmlXPathFalseFunction:
9503 * @ctxt: the XPath Parser context
9504 * @nargs: the number of arguments
9505 *
9506 * Implement the false() XPath function
9507 * boolean false()
9508 */
9509void
9510xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9511 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009512 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009513}
9514
9515/**
9516 * xmlXPathLangFunction:
9517 * @ctxt: the XPath Parser context
9518 * @nargs: the number of arguments
9519 *
9520 * Implement the lang() XPath function
9521 * boolean lang(string)
9522 * The lang function returns true or false depending on whether the
9523 * language of the context node as specified by xml:lang attributes
9524 * is the same as or is a sublanguage of the language specified by
9525 * the argument string. The language of the context node is determined
9526 * by the value of the xml:lang attribute on the context node, or, if
9527 * the context node has no xml:lang attribute, by the value of the
9528 * xml:lang attribute on the nearest ancestor of the context node that
9529 * has an xml:lang attribute. If there is no such attribute, then lang
9530 * returns false. If there is such an attribute, then lang returns
9531 * true if the attribute value is equal to the argument ignoring case,
9532 * or if there is some suffix starting with - such that the attribute
9533 * value is equal to the argument ignoring that suffix of the attribute
9534 * value and ignoring case.
9535 */
9536void
9537xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009538 xmlXPathObjectPtr val = NULL;
9539 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009540 const xmlChar *lang;
9541 int ret = 0;
9542 int i;
9543
9544 CHECK_ARITY(1);
9545 CAST_TO_STRING;
9546 CHECK_TYPE(XPATH_STRING);
9547 val = valuePop(ctxt);
9548 lang = val->stringval;
9549 theLang = xmlNodeGetLang(ctxt->context->node);
9550 if ((theLang != NULL) && (lang != NULL)) {
9551 for (i = 0;lang[i] != 0;i++)
9552 if (toupper(lang[i]) != toupper(theLang[i]))
9553 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009554 if ((theLang[i] == 0) || (theLang[i] == '-'))
9555 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009556 }
9557not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009558 if (theLang != NULL)
9559 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009560
9561 xmlXPathReleaseObject(ctxt->context, val);
9562 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009563}
9564
9565/**
9566 * xmlXPathNumberFunction:
9567 * @ctxt: the XPath Parser context
9568 * @nargs: the number of arguments
9569 *
9570 * Implement the number() XPath function
9571 * number number(object?)
9572 */
9573void
9574xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9575 xmlXPathObjectPtr cur;
9576 double res;
9577
Daniel Veillarda82b1822004-11-08 16:24:57 +00009578 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009579 if (nargs == 0) {
9580 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009581 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009582 } else {
9583 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9584
9585 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009586 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009587 xmlFree(content);
9588 }
9589 return;
9590 }
9591
9592 CHECK_ARITY(1);
9593 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009594 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009595}
9596
9597/**
9598 * xmlXPathSumFunction:
9599 * @ctxt: the XPath Parser context
9600 * @nargs: the number of arguments
9601 *
9602 * Implement the sum() XPath function
9603 * number sum(node-set)
9604 * The sum function returns the sum of the values of the nodes in
9605 * the argument node-set.
9606 */
9607void
9608xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9609 xmlXPathObjectPtr cur;
9610 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009611 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009612
9613 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009614 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009615 ((ctxt->value->type != XPATH_NODESET) &&
9616 (ctxt->value->type != XPATH_XSLT_TREE)))
9617 XP_ERROR(XPATH_INVALID_TYPE);
9618 cur = valuePop(ctxt);
9619
William M. Brack08171912003-12-29 02:52:11 +00009620 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009621 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9622 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009623 }
9624 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009625 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9626 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009627}
9628
William M. Brack3d426662005-04-19 14:40:28 +00009629/*
9630 * To assure working code on multiple platforms, we want to only depend
9631 * upon the characteristic truncation of converting a floating point value
9632 * to an integer. Unfortunately, because of the different storage sizes
9633 * of our internal floating point value (double) and integer (int), we
9634 * can't directly convert (see bug 301162). This macro is a messy
9635 * 'workaround'
9636 */
9637#define XTRUNC(f, v) \
9638 f = fmod((v), INT_MAX); \
9639 f = (v) - (f) + (double)((int)(f));
9640
Owen Taylor3473f882001-02-23 17:55:21 +00009641/**
9642 * xmlXPathFloorFunction:
9643 * @ctxt: the XPath Parser context
9644 * @nargs: the number of arguments
9645 *
9646 * Implement the floor() XPath function
9647 * number floor(number)
9648 * The floor function returns the largest (closest to positive infinity)
9649 * number that is not greater than the argument and that is an integer.
9650 */
9651void
9652xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009653 double f;
9654
Owen Taylor3473f882001-02-23 17:55:21 +00009655 CHECK_ARITY(1);
9656 CAST_TO_NUMBER;
9657 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009658
William M. Brack3d426662005-04-19 14:40:28 +00009659 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009660 if (f != ctxt->value->floatval) {
9661 if (ctxt->value->floatval > 0)
9662 ctxt->value->floatval = f;
9663 else
9664 ctxt->value->floatval = f - 1;
9665 }
Owen Taylor3473f882001-02-23 17:55:21 +00009666}
9667
9668/**
9669 * xmlXPathCeilingFunction:
9670 * @ctxt: the XPath Parser context
9671 * @nargs: the number of arguments
9672 *
9673 * Implement the ceiling() XPath function
9674 * number ceiling(number)
9675 * The ceiling function returns the smallest (closest to negative infinity)
9676 * number that is not less than the argument and that is an integer.
9677 */
9678void
9679xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9680 double f;
9681
9682 CHECK_ARITY(1);
9683 CAST_TO_NUMBER;
9684 CHECK_TYPE(XPATH_NUMBER);
9685
9686#if 0
9687 ctxt->value->floatval = ceil(ctxt->value->floatval);
9688#else
William M. Brack3d426662005-04-19 14:40:28 +00009689 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009690 if (f != ctxt->value->floatval) {
9691 if (ctxt->value->floatval > 0)
9692 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009693 else {
9694 if (ctxt->value->floatval < 0 && f == 0)
9695 ctxt->value->floatval = xmlXPathNZERO;
9696 else
9697 ctxt->value->floatval = f;
9698 }
9699
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009700 }
Owen Taylor3473f882001-02-23 17:55:21 +00009701#endif
9702}
9703
9704/**
9705 * xmlXPathRoundFunction:
9706 * @ctxt: the XPath Parser context
9707 * @nargs: the number of arguments
9708 *
9709 * Implement the round() XPath function
9710 * number round(number)
9711 * The round function returns the number that is closest to the
9712 * argument and that is an integer. If there are two such numbers,
9713 * then the one that is even is returned.
9714 */
9715void
9716xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9717 double f;
9718
9719 CHECK_ARITY(1);
9720 CAST_TO_NUMBER;
9721 CHECK_TYPE(XPATH_NUMBER);
9722
Daniel Veillardcda96922001-08-21 10:56:31 +00009723 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9724 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9725 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009726 (ctxt->value->floatval == 0.0))
9727 return;
9728
William M. Brack3d426662005-04-19 14:40:28 +00009729 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009730 if (ctxt->value->floatval < 0) {
9731 if (ctxt->value->floatval < f - 0.5)
9732 ctxt->value->floatval = f - 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009733 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009734 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009735 if (ctxt->value->floatval == 0)
9736 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009737 } else {
9738 if (ctxt->value->floatval < f + 0.5)
9739 ctxt->value->floatval = f;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009740 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009741 ctxt->value->floatval = f + 1;
9742 }
Owen Taylor3473f882001-02-23 17:55:21 +00009743}
9744
9745/************************************************************************
9746 * *
9747 * The Parser *
9748 * *
9749 ************************************************************************/
9750
9751/*
William M. Brack08171912003-12-29 02:52:11 +00009752 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009753 * implementation.
9754 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009755static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009756static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009757static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009758static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009759static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9760 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009761
9762/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009763 * xmlXPathCurrentChar:
9764 * @ctxt: the XPath parser context
9765 * @cur: pointer to the beginning of the char
9766 * @len: pointer to the length of the char read
9767 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009768 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009769 * bytes in the input buffer.
9770 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009771 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009772 */
9773
9774static int
9775xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9776 unsigned char c;
9777 unsigned int val;
9778 const xmlChar *cur;
9779
9780 if (ctxt == NULL)
9781 return(0);
9782 cur = ctxt->cur;
9783
9784 /*
9785 * We are supposed to handle UTF8, check it's valid
9786 * From rfc2044: encoding of the Unicode values on UTF-8:
9787 *
9788 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9789 * 0000 0000-0000 007F 0xxxxxxx
9790 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009791 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009792 *
9793 * Check for the 0x110000 limit too
9794 */
9795 c = *cur;
9796 if (c & 0x80) {
9797 if ((cur[1] & 0xc0) != 0x80)
9798 goto encoding_error;
9799 if ((c & 0xe0) == 0xe0) {
9800
9801 if ((cur[2] & 0xc0) != 0x80)
9802 goto encoding_error;
9803 if ((c & 0xf0) == 0xf0) {
9804 if (((c & 0xf8) != 0xf0) ||
9805 ((cur[3] & 0xc0) != 0x80))
9806 goto encoding_error;
9807 /* 4-byte code */
9808 *len = 4;
9809 val = (cur[0] & 0x7) << 18;
9810 val |= (cur[1] & 0x3f) << 12;
9811 val |= (cur[2] & 0x3f) << 6;
9812 val |= cur[3] & 0x3f;
9813 } else {
9814 /* 3-byte code */
9815 *len = 3;
9816 val = (cur[0] & 0xf) << 12;
9817 val |= (cur[1] & 0x3f) << 6;
9818 val |= cur[2] & 0x3f;
9819 }
9820 } else {
9821 /* 2-byte code */
9822 *len = 2;
9823 val = (cur[0] & 0x1f) << 6;
9824 val |= cur[1] & 0x3f;
9825 }
9826 if (!IS_CHAR(val)) {
9827 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009828 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009829 return(val);
9830 } else {
9831 /* 1-byte code */
9832 *len = 1;
9833 return((int) *cur);
9834 }
9835encoding_error:
9836 /*
William M. Brack08171912003-12-29 02:52:11 +00009837 * If we detect an UTF8 error that probably means that the
9838 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009839 * declaration header. Report the error and switch the encoding
9840 * to ISO-Latin-1 (if you don't like this policy, just declare the
9841 * encoding !)
9842 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009843 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009844 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009845}
9846
9847/**
Owen Taylor3473f882001-02-23 17:55:21 +00009848 * xmlXPathParseNCName:
9849 * @ctxt: the XPath Parser context
9850 *
9851 * parse an XML namespace non qualified name.
9852 *
9853 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9854 *
9855 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9856 * CombiningChar | Extender
9857 *
9858 * Returns the namespace name or NULL
9859 */
9860
9861xmlChar *
9862xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009863 const xmlChar *in;
9864 xmlChar *ret;
9865 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009866
Daniel Veillarda82b1822004-11-08 16:24:57 +00009867 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009868 /*
9869 * Accelerator for simple ASCII names
9870 */
9871 in = ctxt->cur;
9872 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9873 ((*in >= 0x41) && (*in <= 0x5A)) ||
9874 (*in == '_')) {
9875 in++;
9876 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9877 ((*in >= 0x41) && (*in <= 0x5A)) ||
9878 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009879 (*in == '_') || (*in == '.') ||
9880 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009881 in++;
9882 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9883 (*in == '[') || (*in == ']') || (*in == ':') ||
9884 (*in == '@') || (*in == '*')) {
9885 count = in - ctxt->cur;
9886 if (count == 0)
9887 return(NULL);
9888 ret = xmlStrndup(ctxt->cur, count);
9889 ctxt->cur = in;
9890 return(ret);
9891 }
9892 }
9893 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009894}
9895
Daniel Veillard2156a562001-04-28 12:24:34 +00009896
Owen Taylor3473f882001-02-23 17:55:21 +00009897/**
9898 * xmlXPathParseQName:
9899 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009900 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009901 *
9902 * parse an XML qualified name
9903 *
9904 * [NS 5] QName ::= (Prefix ':')? LocalPart
9905 *
9906 * [NS 6] Prefix ::= NCName
9907 *
9908 * [NS 7] LocalPart ::= NCName
9909 *
9910 * Returns the function returns the local part, and prefix is updated
9911 * to get the Prefix if any.
9912 */
9913
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009914static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009915xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9916 xmlChar *ret = NULL;
9917
9918 *prefix = NULL;
9919 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009920 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009921 *prefix = ret;
9922 NEXT;
9923 ret = xmlXPathParseNCName(ctxt);
9924 }
9925 return(ret);
9926}
9927
9928/**
9929 * xmlXPathParseName:
9930 * @ctxt: the XPath Parser context
9931 *
9932 * parse an XML name
9933 *
9934 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9935 * CombiningChar | Extender
9936 *
9937 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9938 *
9939 * Returns the namespace name or NULL
9940 */
9941
9942xmlChar *
9943xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009944 const xmlChar *in;
9945 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009946 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009947
Daniel Veillarda82b1822004-11-08 16:24:57 +00009948 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009949 /*
9950 * Accelerator for simple ASCII names
9951 */
9952 in = ctxt->cur;
9953 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9954 ((*in >= 0x41) && (*in <= 0x5A)) ||
9955 (*in == '_') || (*in == ':')) {
9956 in++;
9957 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9958 ((*in >= 0x41) && (*in <= 0x5A)) ||
9959 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009960 (*in == '_') || (*in == '-') ||
9961 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009962 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009963 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009964 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009965 if (count > XML_MAX_NAME_LENGTH) {
9966 ctxt->cur = in;
9967 XP_ERRORNULL(XPATH_EXPR_ERROR);
9968 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009969 ret = xmlStrndup(ctxt->cur, count);
9970 ctxt->cur = in;
9971 return(ret);
9972 }
9973 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009974 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009975}
9976
Daniel Veillard61d80a22001-04-27 17:13:01 +00009977static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009978xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009979 xmlChar buf[XML_MAX_NAMELEN + 5];
9980 int len = 0, l;
9981 int c;
9982
9983 /*
9984 * Handler for more complex cases
9985 */
9986 c = CUR_CHAR(l);
9987 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009988 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9989 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009990 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009991 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009992 return(NULL);
9993 }
9994
9995 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9996 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9997 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009998 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009999 (IS_COMBINING(c)) ||
10000 (IS_EXTENDER(c)))) {
10001 COPY_BUF(l,buf,len,c);
10002 NEXTL(l);
10003 c = CUR_CHAR(l);
10004 if (len >= XML_MAX_NAMELEN) {
10005 /*
10006 * Okay someone managed to make a huge name, so he's ready to pay
10007 * for the processing speed.
10008 */
10009 xmlChar *buffer;
10010 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010011
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010012 if (len > XML_MAX_NAME_LENGTH) {
10013 XP_ERRORNULL(XPATH_EXPR_ERROR);
10014 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +000010015 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010016 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010017 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010018 }
10019 memcpy(buffer, buf, len);
10020 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10021 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010022 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +000010023 (IS_COMBINING(c)) ||
10024 (IS_EXTENDER(c))) {
10025 if (len + 10 > max) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010026 if (max > XML_MAX_NAME_LENGTH) {
10027 XP_ERRORNULL(XPATH_EXPR_ERROR);
10028 }
Daniel Veillard61d80a22001-04-27 17:13:01 +000010029 max *= 2;
10030 buffer = (xmlChar *) xmlRealloc(buffer,
10031 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010032 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010033 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010034 }
10035 }
10036 COPY_BUF(l,buffer,len,c);
10037 NEXTL(l);
10038 c = CUR_CHAR(l);
10039 }
10040 buffer[len] = 0;
10041 return(buffer);
10042 }
10043 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010044 if (len == 0)
10045 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010046 return(xmlStrndup(buf, len));
10047}
Daniel Veillard3cd72402002-05-13 10:33:30 +000010048
10049#define MAX_FRAC 20
10050
William M. Brack372a4452004-02-17 13:09:23 +000010051/*
10052 * These are used as divisors for the fractional part of a number.
10053 * Since the table includes 1.0 (representing '0' fractional digits),
10054 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10055 */
10056static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010057 1.0, 10.0, 100.0, 1000.0, 10000.0,
10058 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10059 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10060 100000000000000.0,
10061 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +000010062 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +000010063};
10064
Owen Taylor3473f882001-02-23 17:55:21 +000010065/**
10066 * xmlXPathStringEvalNumber:
10067 * @str: A string to scan
10068 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000010069 * [30a] Float ::= Number ('e' Digits?)?
10070 *
Owen Taylor3473f882001-02-23 17:55:21 +000010071 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010072 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010073 * [31] Digits ::= [0-9]+
10074 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010075 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +000010076 * In complement of the Number expression, this function also handles
10077 * negative values : '-' Number.
10078 *
10079 * Returns the double value.
10080 */
10081double
10082xmlXPathStringEvalNumber(const xmlChar *str) {
10083 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +000010084 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010085 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010086 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010087 int exponent = 0;
10088 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010089#ifdef __GNUC__
10090 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010091 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010092#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010093 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +000010094 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010095 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10096 return(xmlXPathNAN);
10097 }
10098 if (*cur == '-') {
10099 isneg = 1;
10100 cur++;
10101 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010102
10103#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010104 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010105 * tmp/temp is a workaround against a gcc compiler bug
10106 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010107 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010108 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010109 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010110 ret = ret * 10;
10111 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010112 ok = 1;
10113 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010114 temp = (double) tmp;
10115 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010116 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010117#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010118 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010119 while ((*cur >= '0') && (*cur <= '9')) {
10120 ret = ret * 10 + (*cur - '0');
10121 ok = 1;
10122 cur++;
10123 }
10124#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010125
Owen Taylor3473f882001-02-23 17:55:21 +000010126 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010127 int v, frac = 0;
10128 double fraction = 0;
10129
Owen Taylor3473f882001-02-23 17:55:21 +000010130 cur++;
10131 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10132 return(xmlXPathNAN);
10133 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010134 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10135 v = (*cur - '0');
10136 fraction = fraction * 10 + v;
10137 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010138 cur++;
10139 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010140 fraction /= my_pow10[frac];
10141 ret = ret + fraction;
10142 while ((*cur >= '0') && (*cur <= '9'))
10143 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010144 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010145 if ((*cur == 'e') || (*cur == 'E')) {
10146 cur++;
10147 if (*cur == '-') {
10148 is_exponent_negative = 1;
10149 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010150 } else if (*cur == '+') {
10151 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010152 }
10153 while ((*cur >= '0') && (*cur <= '9')) {
10154 exponent = exponent * 10 + (*cur - '0');
10155 cur++;
10156 }
10157 }
William M. Brack76e95df2003-10-18 16:20:14 +000010158 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010159 if (*cur != 0) return(xmlXPathNAN);
10160 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010161 if (is_exponent_negative) exponent = -exponent;
10162 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010163 return(ret);
10164}
10165
10166/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010167 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010168 * @ctxt: the XPath Parser context
10169 *
10170 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010171 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010172 * [31] Digits ::= [0-9]+
10173 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010174 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010175 *
10176 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010177static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010178xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10179{
Owen Taylor3473f882001-02-23 17:55:21 +000010180 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010181 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010182 int exponent = 0;
10183 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010184#ifdef __GNUC__
10185 unsigned long tmp = 0;
10186 double temp;
10187#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010188
10189 CHECK_ERROR;
10190 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10191 XP_ERROR(XPATH_NUMBER_ERROR);
10192 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010193#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010194 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010195 * tmp/temp is a workaround against a gcc compiler bug
10196 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010197 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010198 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010199 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010200 ret = ret * 10;
10201 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010202 ok = 1;
10203 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010204 temp = (double) tmp;
10205 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010206 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010207#else
10208 ret = 0;
10209 while ((CUR >= '0') && (CUR <= '9')) {
10210 ret = ret * 10 + (CUR - '0');
10211 ok = 1;
10212 NEXT;
10213 }
10214#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010215 if (CUR == '.') {
Phil Shaferee32ad32010-11-03 20:53:55 +010010216 int v, frac = 0;
10217 double fraction = 0;
10218
Owen Taylor3473f882001-02-23 17:55:21 +000010219 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010220 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10221 XP_ERROR(XPATH_NUMBER_ERROR);
10222 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010223 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10224 v = (CUR - '0');
10225 fraction = fraction * 10 + v;
10226 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010227 NEXT;
10228 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010229 fraction /= my_pow10[frac];
10230 ret = ret + fraction;
10231 while ((CUR >= '0') && (CUR <= '9'))
10232 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010233 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010234 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010235 NEXT;
10236 if (CUR == '-') {
10237 is_exponent_negative = 1;
10238 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010239 } else if (CUR == '+') {
10240 NEXT;
10241 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010242 while ((CUR >= '0') && (CUR <= '9')) {
10243 exponent = exponent * 10 + (CUR - '0');
10244 NEXT;
10245 }
10246 if (is_exponent_negative)
10247 exponent = -exponent;
10248 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010249 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010250 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010251 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010252}
10253
10254/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010255 * xmlXPathParseLiteral:
10256 * @ctxt: the XPath Parser context
10257 *
10258 * Parse a Literal
10259 *
10260 * [29] Literal ::= '"' [^"]* '"'
10261 * | "'" [^']* "'"
10262 *
10263 * Returns the value found or NULL in case of error
10264 */
10265static xmlChar *
10266xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10267 const xmlChar *q;
10268 xmlChar *ret = NULL;
10269
10270 if (CUR == '"') {
10271 NEXT;
10272 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010273 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010274 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010275 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010276 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010277 } else {
10278 ret = xmlStrndup(q, CUR_PTR - q);
10279 NEXT;
10280 }
10281 } else if (CUR == '\'') {
10282 NEXT;
10283 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010284 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010285 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010286 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010287 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010288 } else {
10289 ret = xmlStrndup(q, CUR_PTR - q);
10290 NEXT;
10291 }
10292 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010293 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010294 }
10295 return(ret);
10296}
10297
10298/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010299 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010300 * @ctxt: the XPath Parser context
10301 *
10302 * Parse a Literal and push it on the stack.
10303 *
10304 * [29] Literal ::= '"' [^"]* '"'
10305 * | "'" [^']* "'"
10306 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010307 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010308 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010309static void
10310xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010311 const xmlChar *q;
10312 xmlChar *ret = NULL;
10313
10314 if (CUR == '"') {
10315 NEXT;
10316 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010317 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010318 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010319 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010320 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10321 } else {
10322 ret = xmlStrndup(q, CUR_PTR - q);
10323 NEXT;
10324 }
10325 } else if (CUR == '\'') {
10326 NEXT;
10327 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010328 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010329 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010330 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010331 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10332 } else {
10333 ret = xmlStrndup(q, CUR_PTR - q);
10334 NEXT;
10335 }
10336 } else {
10337 XP_ERROR(XPATH_START_LITERAL_ERROR);
10338 }
10339 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010340 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010341 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010342 xmlFree(ret);
10343}
10344
10345/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010346 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010347 * @ctxt: the XPath Parser context
10348 *
10349 * Parse a VariableReference, evaluate it and push it on the stack.
10350 *
10351 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010352 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010353 * of any of the types that are possible for the value of an expression,
10354 * and may also be of additional types not specified here.
10355 *
10356 * Early evaluation is possible since:
10357 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010358 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010359 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010360 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010361 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010362static void
10363xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010364 xmlChar *name;
10365 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010366
10367 SKIP_BLANKS;
10368 if (CUR != '$') {
10369 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10370 }
10371 NEXT;
10372 name = xmlXPathParseQName(ctxt, &prefix);
10373 if (name == NULL) {
10374 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10375 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010376 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010377 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10378 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010379 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010380 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10381 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10382 }
Owen Taylor3473f882001-02-23 17:55:21 +000010383}
10384
10385/**
10386 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010387 * @name: a name string
10388 *
10389 * Is the name given a NodeType one.
10390 *
10391 * [38] NodeType ::= 'comment'
10392 * | 'text'
10393 * | 'processing-instruction'
10394 * | 'node'
10395 *
10396 * Returns 1 if true 0 otherwise
10397 */
10398int
10399xmlXPathIsNodeType(const xmlChar *name) {
10400 if (name == NULL)
10401 return(0);
10402
Daniel Veillard1971ee22002-01-31 20:29:19 +000010403 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010404 return(1);
10405 if (xmlStrEqual(name, BAD_CAST "text"))
10406 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010407 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010408 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010409 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010410 return(1);
10411 return(0);
10412}
10413
10414/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010415 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010416 * @ctxt: the XPath Parser context
10417 *
10418 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010419 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010420 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010421 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010422 * pushed on the stack
10423 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010424static void
10425xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010426 xmlChar *name;
10427 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010428 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010429 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010430
10431 name = xmlXPathParseQName(ctxt, &prefix);
10432 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010433 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010434 XP_ERROR(XPATH_EXPR_ERROR);
10435 }
10436 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010437#ifdef DEBUG_EXPR
10438 if (prefix == NULL)
10439 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10440 name);
10441 else
10442 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10443 prefix, name);
10444#endif
10445
Owen Taylor3473f882001-02-23 17:55:21 +000010446 if (CUR != '(') {
10447 XP_ERROR(XPATH_EXPR_ERROR);
10448 }
10449 NEXT;
10450 SKIP_BLANKS;
10451
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010452 /*
10453 * Optimization for count(): we don't need the node-set to be sorted.
10454 */
10455 if ((prefix == NULL) && (name[0] == 'c') &&
10456 xmlStrEqual(name, BAD_CAST "count"))
10457 {
10458 sort = 0;
10459 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010460 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010461 if (CUR != ')') {
10462 while (CUR != 0) {
10463 int op1 = ctxt->comp->last;
10464 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010465 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010466 if (ctxt->error != XPATH_EXPRESSION_OK) {
10467 xmlFree(name);
10468 xmlFree(prefix);
10469 return;
10470 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010471 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10472 nbargs++;
10473 if (CUR == ')') break;
10474 if (CUR != ',') {
10475 XP_ERROR(XPATH_EXPR_ERROR);
10476 }
10477 NEXT;
10478 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010479 }
Owen Taylor3473f882001-02-23 17:55:21 +000010480 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010481 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10482 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010483 NEXT;
10484 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010485}
10486
10487/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010488 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010489 * @ctxt: the XPath Parser context
10490 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010491 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010492 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010493 * | Literal
10494 * | Number
10495 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010496 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010497 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010498 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010499static void
10500xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010501 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010502 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010503 else if (CUR == '(') {
10504 NEXT;
10505 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010506 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010507 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010508 if (CUR != ')') {
10509 XP_ERROR(XPATH_EXPR_ERROR);
10510 }
10511 NEXT;
10512 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010513 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010514 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010515 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010516 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010517 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010518 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010519 }
10520 SKIP_BLANKS;
10521}
10522
10523/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010524 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010525 * @ctxt: the XPath Parser context
10526 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010527 * [20] FilterExpr ::= PrimaryExpr
10528 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010529 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010530 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010531 * Square brackets are used to filter expressions in the same way that
10532 * they are used in location paths. It is an error if the expression to
10533 * be filtered does not evaluate to a node-set. The context node list
10534 * used for evaluating the expression in square brackets is the node-set
10535 * to be filtered listed in document order.
10536 */
10537
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010538static void
10539xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10540 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010541 CHECK_ERROR;
10542 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010543
Owen Taylor3473f882001-02-23 17:55:21 +000010544 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010545 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010546 SKIP_BLANKS;
10547 }
10548
Daniel Veillard45490ae2008-07-29 09:13:19 +000010549
Owen Taylor3473f882001-02-23 17:55:21 +000010550}
10551
10552/**
10553 * xmlXPathScanName:
10554 * @ctxt: the XPath Parser context
10555 *
10556 * Trickery: parse an XML name but without consuming the input flow
10557 * Needed to avoid insanity in the parser state.
10558 *
10559 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10560 * CombiningChar | Extender
10561 *
10562 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10563 *
10564 * [6] Names ::= Name (S Name)*
10565 *
10566 * Returns the Name parsed or NULL
10567 */
10568
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010569static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010570xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010571 int len = 0, l;
10572 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010573 const xmlChar *cur;
10574 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010575
Daniel Veillard03226812004-11-01 14:55:21 +000010576 cur = ctxt->cur;
10577
10578 c = CUR_CHAR(l);
10579 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10580 (!IS_LETTER(c) && (c != '_') &&
10581 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010582 return(NULL);
10583 }
10584
Daniel Veillard03226812004-11-01 14:55:21 +000010585 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10586 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10587 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010588 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010589 (IS_COMBINING(c)) ||
10590 (IS_EXTENDER(c)))) {
10591 len += l;
10592 NEXTL(l);
10593 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010594 }
Daniel Veillard03226812004-11-01 14:55:21 +000010595 ret = xmlStrndup(cur, ctxt->cur - cur);
10596 ctxt->cur = cur;
10597 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010598}
10599
10600/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010601 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010602 * @ctxt: the XPath Parser context
10603 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010604 * [19] PathExpr ::= LocationPath
10605 * | FilterExpr
10606 * | FilterExpr '/' RelativeLocationPath
10607 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010608 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010609 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010610 * The / operator and // operators combine an arbitrary expression
10611 * and a relative location path. It is an error if the expression
10612 * does not evaluate to a node-set.
10613 * The / operator does composition in the same way as when / is
10614 * used in a location path. As in location paths, // is short for
10615 * /descendant-or-self::node()/.
10616 */
10617
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010618static void
10619xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010620 int lc = 1; /* Should we branch to LocationPath ? */
10621 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10622
10623 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010624 if ((CUR == '$') || (CUR == '(') ||
10625 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010626 (CUR == '\'') || (CUR == '"') ||
10627 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010628 lc = 0;
10629 } else if (CUR == '*') {
10630 /* relative or absolute location path */
10631 lc = 1;
10632 } else if (CUR == '/') {
10633 /* relative or absolute location path */
10634 lc = 1;
10635 } else if (CUR == '@') {
10636 /* relative abbreviated attribute location path */
10637 lc = 1;
10638 } else if (CUR == '.') {
10639 /* relative abbreviated attribute location path */
10640 lc = 1;
10641 } else {
10642 /*
10643 * Problem is finding if we have a name here whether it's:
10644 * - a nodetype
10645 * - a function call in which case it's followed by '('
10646 * - an axis in which case it's followed by ':'
10647 * - a element name
10648 * We do an a priori analysis here rather than having to
10649 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010650 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010651 * read/write/debug.
10652 */
10653 SKIP_BLANKS;
10654 name = xmlXPathScanName(ctxt);
10655 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10656#ifdef DEBUG_STEP
10657 xmlGenericError(xmlGenericErrorContext,
10658 "PathExpr: Axis\n");
10659#endif
10660 lc = 1;
10661 xmlFree(name);
10662 } else if (name != NULL) {
10663 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010664
Daniel Veillard45490ae2008-07-29 09:13:19 +000010665
Owen Taylor3473f882001-02-23 17:55:21 +000010666 while (NXT(len) != 0) {
10667 if (NXT(len) == '/') {
10668 /* element name */
10669#ifdef DEBUG_STEP
10670 xmlGenericError(xmlGenericErrorContext,
10671 "PathExpr: AbbrRelLocation\n");
10672#endif
10673 lc = 1;
10674 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010675 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010676 /* ignore blanks */
10677 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010678 } else if (NXT(len) == ':') {
10679#ifdef DEBUG_STEP
10680 xmlGenericError(xmlGenericErrorContext,
10681 "PathExpr: AbbrRelLocation\n");
10682#endif
10683 lc = 1;
10684 break;
10685 } else if ((NXT(len) == '(')) {
10686 /* Note Type or Function */
10687 if (xmlXPathIsNodeType(name)) {
10688#ifdef DEBUG_STEP
10689 xmlGenericError(xmlGenericErrorContext,
10690 "PathExpr: Type search\n");
10691#endif
10692 lc = 1;
10693 } else {
10694#ifdef DEBUG_STEP
10695 xmlGenericError(xmlGenericErrorContext,
10696 "PathExpr: function call\n");
10697#endif
10698 lc = 0;
10699 }
10700 break;
10701 } else if ((NXT(len) == '[')) {
10702 /* element name */
10703#ifdef DEBUG_STEP
10704 xmlGenericError(xmlGenericErrorContext,
10705 "PathExpr: AbbrRelLocation\n");
10706#endif
10707 lc = 1;
10708 break;
10709 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10710 (NXT(len) == '=')) {
10711 lc = 1;
10712 break;
10713 } else {
10714 lc = 1;
10715 break;
10716 }
10717 len++;
10718 }
10719 if (NXT(len) == 0) {
10720#ifdef DEBUG_STEP
10721 xmlGenericError(xmlGenericErrorContext,
10722 "PathExpr: AbbrRelLocation\n");
10723#endif
10724 /* element name */
10725 lc = 1;
10726 }
10727 xmlFree(name);
10728 } else {
William M. Brack08171912003-12-29 02:52:11 +000010729 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010730 XP_ERROR(XPATH_EXPR_ERROR);
10731 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010732 }
Owen Taylor3473f882001-02-23 17:55:21 +000010733
10734 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010735 if (CUR == '/') {
10736 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10737 } else {
10738 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010739 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010740 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010741 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010742 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010743 CHECK_ERROR;
10744 if ((CUR == '/') && (NXT(1) == '/')) {
10745 SKIP(2);
10746 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010747
10748 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10749 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10750 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10751
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010752 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010753 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010754 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010755 }
10756 }
10757 SKIP_BLANKS;
10758}
10759
10760/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010761 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010762 * @ctxt: the XPath Parser context
10763 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010764 * [18] UnionExpr ::= PathExpr
10765 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010766 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010767 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010768 */
10769
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010770static void
10771xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10772 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010773 CHECK_ERROR;
10774 SKIP_BLANKS;
10775 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010776 int op1 = ctxt->comp->last;
10777 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010778
10779 NEXT;
10780 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010781 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010782
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010783 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10784
Owen Taylor3473f882001-02-23 17:55:21 +000010785 SKIP_BLANKS;
10786 }
Owen Taylor3473f882001-02-23 17:55:21 +000010787}
10788
10789/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010790 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010791 * @ctxt: the XPath Parser context
10792 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010793 * [27] UnaryExpr ::= UnionExpr
10794 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010795 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010796 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010797 */
10798
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010799static void
10800xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010801 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010802 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010803
10804 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010805 while (CUR == '-') {
10806 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010807 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010808 NEXT;
10809 SKIP_BLANKS;
10810 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010811
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010812 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010813 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010814 if (found) {
10815 if (minus)
10816 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10817 else
10818 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010819 }
10820}
10821
10822/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010823 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010824 * @ctxt: the XPath Parser context
10825 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010826 * [26] MultiplicativeExpr ::= UnaryExpr
10827 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10828 * | MultiplicativeExpr 'div' UnaryExpr
10829 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010830 * [34] MultiplyOperator ::= '*'
10831 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010832 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010833 */
10834
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010835static void
10836xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10837 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010838 CHECK_ERROR;
10839 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010840 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010841 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10842 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10843 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010844 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010845
10846 if (CUR == '*') {
10847 op = 0;
10848 NEXT;
10849 } else if (CUR == 'd') {
10850 op = 1;
10851 SKIP(3);
10852 } else if (CUR == 'm') {
10853 op = 2;
10854 SKIP(3);
10855 }
10856 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010857 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010858 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010859 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010860 SKIP_BLANKS;
10861 }
10862}
10863
10864/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010865 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010866 * @ctxt: the XPath Parser context
10867 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010868 * [25] AdditiveExpr ::= MultiplicativeExpr
10869 * | AdditiveExpr '+' MultiplicativeExpr
10870 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010871 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010872 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010873 */
10874
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010875static void
10876xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010877
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010878 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010879 CHECK_ERROR;
10880 SKIP_BLANKS;
10881 while ((CUR == '+') || (CUR == '-')) {
10882 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010883 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010884
10885 if (CUR == '+') plus = 1;
10886 else plus = 0;
10887 NEXT;
10888 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010889 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010890 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010891 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010892 SKIP_BLANKS;
10893 }
10894}
10895
10896/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010897 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010898 * @ctxt: the XPath Parser context
10899 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010900 * [24] RelationalExpr ::= AdditiveExpr
10901 * | RelationalExpr '<' AdditiveExpr
10902 * | RelationalExpr '>' AdditiveExpr
10903 * | RelationalExpr '<=' AdditiveExpr
10904 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010905 *
10906 * A <= B > C is allowed ? Answer from James, yes with
10907 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10908 * which is basically what got implemented.
10909 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010910 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010911 * on the stack
10912 */
10913
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010914static void
10915xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10916 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010917 CHECK_ERROR;
10918 SKIP_BLANKS;
10919 while ((CUR == '<') ||
10920 (CUR == '>') ||
10921 ((CUR == '<') && (NXT(1) == '=')) ||
10922 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010923 int inf, strict;
10924 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010925
10926 if (CUR == '<') inf = 1;
10927 else inf = 0;
10928 if (NXT(1) == '=') strict = 0;
10929 else strict = 1;
10930 NEXT;
10931 if (!strict) NEXT;
10932 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010933 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010934 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010935 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010936 SKIP_BLANKS;
10937 }
10938}
10939
10940/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010941 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010942 * @ctxt: the XPath Parser context
10943 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010944 * [23] EqualityExpr ::= RelationalExpr
10945 * | EqualityExpr '=' RelationalExpr
10946 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010947 *
10948 * A != B != C is allowed ? Answer from James, yes with
10949 * (RelationalExpr = RelationalExpr) = RelationalExpr
10950 * (RelationalExpr != RelationalExpr) != RelationalExpr
10951 * which is basically what got implemented.
10952 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010953 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010954 *
10955 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010956static void
10957xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10958 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010959 CHECK_ERROR;
10960 SKIP_BLANKS;
10961 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010962 int eq;
10963 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010964
10965 if (CUR == '=') eq = 1;
10966 else eq = 0;
10967 NEXT;
10968 if (!eq) NEXT;
10969 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010970 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010971 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010972 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010973 SKIP_BLANKS;
10974 }
10975}
10976
10977/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010978 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010979 * @ctxt: the XPath Parser context
10980 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010981 * [22] AndExpr ::= EqualityExpr
10982 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010983 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010984 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010985 *
10986 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010987static void
10988xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10989 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010990 CHECK_ERROR;
10991 SKIP_BLANKS;
10992 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010993 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010994 SKIP(3);
10995 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010996 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010997 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010998 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010999 SKIP_BLANKS;
11000 }
11001}
11002
11003/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000011004 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000011005 * @ctxt: the XPath Parser context
11006 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011007 * [14] Expr ::= OrExpr
11008 * [21] OrExpr ::= AndExpr
11009 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000011010 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011011 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000011012 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011013static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011014xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011015 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011016 CHECK_ERROR;
11017 SKIP_BLANKS;
11018 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011019 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011020 SKIP(2);
11021 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011022 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011023 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011024 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011025 SKIP_BLANKS;
11026 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011027 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011028 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011029 /*
11030 * This is the main place to eliminate sorting for
11031 * operations which don't require a sorted node-set.
11032 * E.g. count().
11033 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011034 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11035 }
Owen Taylor3473f882001-02-23 17:55:21 +000011036}
11037
11038/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011039 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000011040 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011041 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000011042 *
11043 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000011044 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000011045 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011046 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000011047 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011048static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011049xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011050 int op1 = ctxt->comp->last;
11051
11052 SKIP_BLANKS;
11053 if (CUR != '[') {
11054 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11055 }
11056 NEXT;
11057 SKIP_BLANKS;
11058
11059 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011060 /*
11061 * This call to xmlXPathCompileExpr() will deactivate sorting
11062 * of the predicate result.
11063 * TODO: Sorting is still activated for filters, since I'm not
11064 * sure if needed. Normally sorting should not be needed, since
11065 * a filter can only diminish the number of items in a sequence,
11066 * but won't change its order; so if the initial sequence is sorted,
11067 * subsequent sorting is not needed.
11068 */
11069 if (! filter)
11070 xmlXPathCompileExpr(ctxt, 0);
11071 else
11072 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011073 CHECK_ERROR;
11074
11075 if (CUR != ']') {
11076 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11077 }
11078
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011079 if (filter)
11080 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11081 else
11082 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011083
11084 NEXT;
11085 SKIP_BLANKS;
11086}
11087
11088/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011089 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011090 * @ctxt: the XPath Parser context
11091 * @test: pointer to a xmlXPathTestVal
11092 * @type: pointer to a xmlXPathTypeVal
11093 * @prefix: placeholder for a possible name prefix
11094 *
11095 * [7] NodeTest ::= NameTest
11096 * | NodeType '(' ')'
11097 * | 'processing-instruction' '(' Literal ')'
11098 *
11099 * [37] NameTest ::= '*'
11100 * | NCName ':' '*'
11101 * | QName
11102 * [38] NodeType ::= 'comment'
11103 * | 'text'
11104 * | 'processing-instruction'
11105 * | 'node'
11106 *
William M. Brack08171912003-12-29 02:52:11 +000011107 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011108 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011109static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011110xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11111 xmlXPathTypeVal *type, const xmlChar **prefix,
11112 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011113 int blanks;
11114
11115 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11116 STRANGE;
11117 return(NULL);
11118 }
William M. Brack78637da2003-07-31 14:47:38 +000011119 *type = (xmlXPathTypeVal) 0;
11120 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011121 *prefix = NULL;
11122 SKIP_BLANKS;
11123
11124 if ((name == NULL) && (CUR == '*')) {
11125 /*
11126 * All elements
11127 */
11128 NEXT;
11129 *test = NODE_TEST_ALL;
11130 return(NULL);
11131 }
11132
11133 if (name == NULL)
11134 name = xmlXPathParseNCName(ctxt);
11135 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011136 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011137 }
11138
William M. Brack76e95df2003-10-18 16:20:14 +000011139 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011140 SKIP_BLANKS;
11141 if (CUR == '(') {
11142 NEXT;
11143 /*
11144 * NodeType or PI search
11145 */
11146 if (xmlStrEqual(name, BAD_CAST "comment"))
11147 *type = NODE_TYPE_COMMENT;
11148 else if (xmlStrEqual(name, BAD_CAST "node"))
11149 *type = NODE_TYPE_NODE;
11150 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11151 *type = NODE_TYPE_PI;
11152 else if (xmlStrEqual(name, BAD_CAST "text"))
11153 *type = NODE_TYPE_TEXT;
11154 else {
11155 if (name != NULL)
11156 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011157 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011158 }
11159
11160 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011161
Owen Taylor3473f882001-02-23 17:55:21 +000011162 SKIP_BLANKS;
11163 if (*type == NODE_TYPE_PI) {
11164 /*
11165 * Specific case: search a PI by name.
11166 */
Owen Taylor3473f882001-02-23 17:55:21 +000011167 if (name != NULL)
11168 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011169 name = NULL;
11170 if (CUR != ')') {
11171 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011172 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011173 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011174 SKIP_BLANKS;
11175 }
Owen Taylor3473f882001-02-23 17:55:21 +000011176 }
11177 if (CUR != ')') {
11178 if (name != NULL)
11179 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011180 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011181 }
11182 NEXT;
11183 return(name);
11184 }
11185 *test = NODE_TEST_NAME;
11186 if ((!blanks) && (CUR == ':')) {
11187 NEXT;
11188
11189 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011190 * Since currently the parser context don't have a
11191 * namespace list associated:
11192 * The namespace name for this prefix can be computed
11193 * only at evaluation time. The compilation is done
11194 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011195 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011196#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011197 *prefix = xmlXPathNsLookup(ctxt->context, name);
11198 if (name != NULL)
11199 xmlFree(name);
11200 if (*prefix == NULL) {
11201 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11202 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011203#else
11204 *prefix = name;
11205#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011206
11207 if (CUR == '*') {
11208 /*
11209 * All elements
11210 */
11211 NEXT;
11212 *test = NODE_TEST_ALL;
11213 return(NULL);
11214 }
11215
11216 name = xmlXPathParseNCName(ctxt);
11217 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011218 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011219 }
11220 }
11221 return(name);
11222}
11223
11224/**
11225 * xmlXPathIsAxisName:
11226 * @name: a preparsed name token
11227 *
11228 * [6] AxisName ::= 'ancestor'
11229 * | 'ancestor-or-self'
11230 * | 'attribute'
11231 * | 'child'
11232 * | 'descendant'
11233 * | 'descendant-or-self'
11234 * | 'following'
11235 * | 'following-sibling'
11236 * | 'namespace'
11237 * | 'parent'
11238 * | 'preceding'
11239 * | 'preceding-sibling'
11240 * | 'self'
11241 *
11242 * Returns the axis or 0
11243 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011244static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011245xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011246 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011247 switch (name[0]) {
11248 case 'a':
11249 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11250 ret = AXIS_ANCESTOR;
11251 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11252 ret = AXIS_ANCESTOR_OR_SELF;
11253 if (xmlStrEqual(name, BAD_CAST "attribute"))
11254 ret = AXIS_ATTRIBUTE;
11255 break;
11256 case 'c':
11257 if (xmlStrEqual(name, BAD_CAST "child"))
11258 ret = AXIS_CHILD;
11259 break;
11260 case 'd':
11261 if (xmlStrEqual(name, BAD_CAST "descendant"))
11262 ret = AXIS_DESCENDANT;
11263 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11264 ret = AXIS_DESCENDANT_OR_SELF;
11265 break;
11266 case 'f':
11267 if (xmlStrEqual(name, BAD_CAST "following"))
11268 ret = AXIS_FOLLOWING;
11269 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11270 ret = AXIS_FOLLOWING_SIBLING;
11271 break;
11272 case 'n':
11273 if (xmlStrEqual(name, BAD_CAST "namespace"))
11274 ret = AXIS_NAMESPACE;
11275 break;
11276 case 'p':
11277 if (xmlStrEqual(name, BAD_CAST "parent"))
11278 ret = AXIS_PARENT;
11279 if (xmlStrEqual(name, BAD_CAST "preceding"))
11280 ret = AXIS_PRECEDING;
11281 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11282 ret = AXIS_PRECEDING_SIBLING;
11283 break;
11284 case 's':
11285 if (xmlStrEqual(name, BAD_CAST "self"))
11286 ret = AXIS_SELF;
11287 break;
11288 }
11289 return(ret);
11290}
11291
11292/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011293 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011294 * @ctxt: the XPath Parser context
11295 *
11296 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011297 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011298 *
11299 * [12] AbbreviatedStep ::= '.' | '..'
11300 *
11301 * [5] AxisSpecifier ::= AxisName '::'
11302 * | AbbreviatedAxisSpecifier
11303 *
11304 * [13] AbbreviatedAxisSpecifier ::= '@'?
11305 *
11306 * Modified for XPtr range support as:
11307 *
11308 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11309 * | AbbreviatedStep
11310 * | 'range-to' '(' Expr ')' Predicate*
11311 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011312 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011313 * A location step of . is short for self::node(). This is
11314 * particularly useful in conjunction with //. For example, the
11315 * location path .//para is short for
11316 * self::node()/descendant-or-self::node()/child::para
11317 * and so will select all para descendant elements of the context
11318 * node.
11319 * Similarly, a location step of .. is short for parent::node().
11320 * For example, ../title is short for parent::node()/child::title
11321 * and so will select the title children of the parent of the context
11322 * node.
11323 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011324static void
11325xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011326#ifdef LIBXML_XPTR_ENABLED
11327 int rangeto = 0;
11328 int op2 = -1;
11329#endif
11330
Owen Taylor3473f882001-02-23 17:55:21 +000011331 SKIP_BLANKS;
11332 if ((CUR == '.') && (NXT(1) == '.')) {
11333 SKIP(2);
11334 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011335 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11336 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011337 } else if (CUR == '.') {
11338 NEXT;
11339 SKIP_BLANKS;
11340 } else {
11341 xmlChar *name = NULL;
11342 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011343 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011344 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011345 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011346 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011347
11348 /*
11349 * The modification needed for XPointer change to the production
11350 */
11351#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011352 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011353 name = xmlXPathParseNCName(ctxt);
11354 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011355 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011356 xmlFree(name);
11357 SKIP_BLANKS;
11358 if (CUR != '(') {
11359 XP_ERROR(XPATH_EXPR_ERROR);
11360 }
11361 NEXT;
11362 SKIP_BLANKS;
11363
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011364 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011365 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011366 CHECK_ERROR;
11367
11368 SKIP_BLANKS;
11369 if (CUR != ')') {
11370 XP_ERROR(XPATH_EXPR_ERROR);
11371 }
11372 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011373 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011374 goto eval_predicates;
11375 }
11376 }
11377#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011378 if (CUR == '*') {
11379 axis = AXIS_CHILD;
11380 } else {
11381 if (name == NULL)
11382 name = xmlXPathParseNCName(ctxt);
11383 if (name != NULL) {
11384 axis = xmlXPathIsAxisName(name);
11385 if (axis != 0) {
11386 SKIP_BLANKS;
11387 if ((CUR == ':') && (NXT(1) == ':')) {
11388 SKIP(2);
11389 xmlFree(name);
11390 name = NULL;
11391 } else {
11392 /* an element name can conflict with an axis one :-\ */
11393 axis = AXIS_CHILD;
11394 }
Owen Taylor3473f882001-02-23 17:55:21 +000011395 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011396 axis = AXIS_CHILD;
11397 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011398 } else if (CUR == '@') {
11399 NEXT;
11400 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011401 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011402 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011403 }
Owen Taylor3473f882001-02-23 17:55:21 +000011404 }
11405
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011406 if (ctxt->error != XPATH_EXPRESSION_OK) {
11407 xmlFree(name);
11408 return;
11409 }
Owen Taylor3473f882001-02-23 17:55:21 +000011410
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011411 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011412 if (test == 0)
11413 return;
11414
Daniel Veillarded6c5492005-07-23 15:00:22 +000011415 if ((prefix != NULL) && (ctxt->context != NULL) &&
11416 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11417 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11418 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11419 }
11420 }
Owen Taylor3473f882001-02-23 17:55:21 +000011421#ifdef DEBUG_STEP
11422 xmlGenericError(xmlGenericErrorContext,
11423 "Basis : computing new set\n");
11424#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011425
Owen Taylor3473f882001-02-23 17:55:21 +000011426#ifdef DEBUG_STEP
11427 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011428 if (ctxt->value == NULL)
11429 xmlGenericError(xmlGenericErrorContext, "no value\n");
11430 else if (ctxt->value->nodesetval == NULL)
11431 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11432 else
11433 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011434#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011435
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011436#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011437eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011438#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011439 op1 = ctxt->comp->last;
11440 ctxt->comp->last = -1;
11441
Owen Taylor3473f882001-02-23 17:55:21 +000011442 SKIP_BLANKS;
11443 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011444 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011445 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011446
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011447#ifdef LIBXML_XPTR_ENABLED
11448 if (rangeto) {
11449 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11450 } else
11451#endif
11452 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11453 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011454
Owen Taylor3473f882001-02-23 17:55:21 +000011455 }
11456#ifdef DEBUG_STEP
11457 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011458 if (ctxt->value == NULL)
11459 xmlGenericError(xmlGenericErrorContext, "no value\n");
11460 else if (ctxt->value->nodesetval == NULL)
11461 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11462 else
11463 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11464 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011465#endif
11466}
11467
11468/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011469 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011470 * @ctxt: the XPath Parser context
11471 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011472 * [3] RelativeLocationPath ::= Step
11473 * | RelativeLocationPath '/' Step
11474 * | AbbreviatedRelativeLocationPath
11475 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011476 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011477 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011478 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011479static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011480xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011481(xmlXPathParserContextPtr ctxt) {
11482 SKIP_BLANKS;
11483 if ((CUR == '/') && (NXT(1) == '/')) {
11484 SKIP(2);
11485 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011486 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11487 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011488 } else if (CUR == '/') {
11489 NEXT;
11490 SKIP_BLANKS;
11491 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011492 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011493 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011494 SKIP_BLANKS;
11495 while (CUR == '/') {
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,
Owen Taylor3473f882001-02-23 17:55:21 +000011500 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011501 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011502 } else if (CUR == '/') {
11503 NEXT;
11504 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011505 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011506 }
11507 SKIP_BLANKS;
11508 }
11509}
11510
11511/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011512 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011513 * @ctxt: the XPath Parser context
11514 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011515 * [1] LocationPath ::= RelativeLocationPath
11516 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011517 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011518 * | AbbreviatedAbsoluteLocationPath
11519 * [10] AbbreviatedAbsoluteLocationPath ::=
11520 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011521 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011522 * Compile a location path
11523 *
Owen Taylor3473f882001-02-23 17:55:21 +000011524 * // is short for /descendant-or-self::node()/. For example,
11525 * //para is short for /descendant-or-self::node()/child::para and
11526 * so will select any para element in the document (even a para element
11527 * that is a document element will be selected by //para since the
11528 * document element node is a child of the root node); div//para is
11529 * short for div/descendant-or-self::node()/child::para and so will
11530 * select all para descendants of div children.
11531 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011532static void
11533xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011534 SKIP_BLANKS;
11535 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011536 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011537 } else {
11538 while (CUR == '/') {
11539 if ((CUR == '/') && (NXT(1) == '/')) {
11540 SKIP(2);
11541 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011542 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11543 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011544 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011545 } else if (CUR == '/') {
11546 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011547 SKIP_BLANKS;
11548 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011549 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011550 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011551 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011552 }
Martin729601f2009-10-12 22:42:26 +020011553 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011554 }
11555 }
11556}
11557
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011558/************************************************************************
11559 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011560 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011561 * *
11562 ************************************************************************/
11563
Daniel Veillardf06307e2001-07-03 10:35:50 +000011564static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011565xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11566
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011567#ifdef DEBUG_STEP
11568static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011569xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011570 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011571{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011572 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011573 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011574 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011575 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011576 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011577 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011578 xmlGenericError(xmlGenericErrorContext,
11579 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011580 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011581 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011582 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011583 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011584 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011585 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011586 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011587 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011588 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011589 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011590 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011591 xmlGenericError(xmlGenericErrorContext,
11592 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011593 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011594 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011595 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011596 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011597 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011598 xmlGenericError(xmlGenericErrorContext,
11599 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011600 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011601 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011602 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011603 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011604 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011605 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011606 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011607 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011608 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011609 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011610 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011611 xmlGenericError(xmlGenericErrorContext,
11612 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011613 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011614 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011615 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011616 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011617 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011618 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011619 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011620 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011621 case NODE_TEST_NONE:
11622 xmlGenericError(xmlGenericErrorContext,
11623 " searching for none !!!\n");
11624 break;
11625 case NODE_TEST_TYPE:
11626 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011627 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011628 break;
11629 case NODE_TEST_PI:
11630 xmlGenericError(xmlGenericErrorContext,
11631 " searching for PI !!!\n");
11632 break;
11633 case NODE_TEST_ALL:
11634 xmlGenericError(xmlGenericErrorContext,
11635 " searching for *\n");
11636 break;
11637 case NODE_TEST_NS:
11638 xmlGenericError(xmlGenericErrorContext,
11639 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011640 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011641 break;
11642 case NODE_TEST_NAME:
11643 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011644 " searching for name %s\n", op->value5);
11645 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011646 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011647 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011648 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011649 }
11650 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011651}
11652#endif /* DEBUG_STEP */
11653
11654static int
11655xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11656 xmlXPathStepOpPtr op,
11657 xmlNodeSetPtr set,
11658 int contextSize,
11659 int hasNsNodes)
11660{
11661 if (op->ch1 != -1) {
11662 xmlXPathCompExprPtr comp = ctxt->comp;
11663 /*
11664 * Process inner predicates first.
11665 */
11666 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11667 /*
11668 * TODO: raise an internal error.
11669 */
11670 }
11671 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11672 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11673 CHECK_ERROR0;
11674 if (contextSize <= 0)
11675 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011676 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011677 if (op->ch2 != -1) {
11678 xmlXPathContextPtr xpctxt = ctxt->context;
11679 xmlNodePtr contextNode, oldContextNode;
11680 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011681 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011682 xmlXPathStepOpPtr exprOp;
11683 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11684
11685#ifdef LIBXML_XPTR_ENABLED
11686 /*
11687 * URGENT TODO: Check the following:
11688 * We don't expect location sets if evaluating prediates, right?
11689 * Only filters should expect location sets, right?
11690 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011691#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011692 /*
11693 * SPEC XPath 1.0:
11694 * "For each node in the node-set to be filtered, the
11695 * PredicateExpr is evaluated with that node as the
11696 * context node, with the number of nodes in the
11697 * node-set as the context size, and with the proximity
11698 * position of the node in the node-set with respect to
11699 * the axis as the context position;"
11700 * @oldset is the node-set" to be filtered.
11701 *
11702 * SPEC XPath 1.0:
11703 * "only predicates change the context position and
11704 * context size (see [2.4 Predicates])."
11705 * Example:
11706 * node-set context pos
11707 * nA 1
11708 * nB 2
11709 * nC 3
11710 * After applying predicate [position() > 1] :
11711 * node-set context pos
11712 * nB 1
11713 * nC 2
11714 */
11715 oldContextNode = xpctxt->node;
11716 oldContextDoc = xpctxt->doc;
11717 /*
11718 * Get the expression of this predicate.
11719 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011720 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011721 newContextSize = 0;
11722 for (i = 0; i < set->nodeNr; i++) {
11723 if (set->nodeTab[i] == NULL)
11724 continue;
11725
11726 contextNode = set->nodeTab[i];
11727 xpctxt->node = contextNode;
11728 xpctxt->contextSize = contextSize;
11729 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011730
11731 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011732 * Also set the xpath document in case things like
11733 * key() are evaluated in the predicate.
11734 */
11735 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11736 (contextNode->doc != NULL))
11737 xpctxt->doc = contextNode->doc;
11738 /*
11739 * Evaluate the predicate expression with 1 context node
11740 * at a time; this node is packaged into a node set; this
11741 * node set is handed over to the evaluation mechanism.
11742 */
11743 if (contextObj == NULL)
11744 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011745 else {
11746 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11747 contextNode) < 0) {
11748 ctxt->error = XPATH_MEMORY_ERROR;
11749 goto evaluation_exit;
11750 }
11751 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011752
11753 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011754
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011755 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011756
William M. Brack0bcec062007-02-14 02:15:19 +000011757 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11758 xmlXPathNodeSetClear(set, hasNsNodes);
11759 newContextSize = 0;
11760 goto evaluation_exit;
11761 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011762
11763 if (res != 0) {
11764 newContextSize++;
11765 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011766 /*
11767 * Remove the entry from the initial node set.
11768 */
11769 set->nodeTab[i] = NULL;
11770 if (contextNode->type == XML_NAMESPACE_DECL)
11771 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011772 }
11773 if (ctxt->value == contextObj) {
11774 /*
11775 * Don't free the temporary XPath object holding the
11776 * context node, in order to avoid massive recreation
11777 * inside this loop.
11778 */
11779 valuePop(ctxt);
11780 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11781 } else {
11782 /*
11783 * TODO: The object was lost in the evaluation machinery.
11784 * Can this happen? Maybe in internal-error cases.
11785 */
11786 contextObj = NULL;
11787 }
11788 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011789
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011790 if (contextObj != NULL) {
11791 if (ctxt->value == contextObj)
11792 valuePop(ctxt);
11793 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011794 }
William M. Brack0bcec062007-02-14 02:15:19 +000011795evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011796 if (exprRes != NULL)
11797 xmlXPathReleaseObject(ctxt->context, exprRes);
11798 /*
11799 * Reset/invalidate the context.
11800 */
11801 xpctxt->node = oldContextNode;
11802 xpctxt->doc = oldContextDoc;
11803 xpctxt->contextSize = -1;
11804 xpctxt->proximityPosition = -1;
11805 return(newContextSize);
11806 }
11807 return(contextSize);
11808}
11809
11810static int
11811xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11812 xmlXPathStepOpPtr op,
11813 xmlNodeSetPtr set,
11814 int contextSize,
11815 int minPos,
11816 int maxPos,
11817 int hasNsNodes)
11818{
11819 if (op->ch1 != -1) {
11820 xmlXPathCompExprPtr comp = ctxt->comp;
11821 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11822 /*
11823 * TODO: raise an internal error.
11824 */
11825 }
11826 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11827 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11828 CHECK_ERROR0;
11829 if (contextSize <= 0)
11830 return(0);
11831 }
11832 /*
11833 * Check if the node set contains a sufficient number of nodes for
11834 * the requested range.
11835 */
11836 if (contextSize < minPos) {
11837 xmlXPathNodeSetClear(set, hasNsNodes);
11838 return(0);
11839 }
11840 if (op->ch2 == -1) {
11841 /*
11842 * TODO: Can this ever happen?
11843 */
11844 return (contextSize);
11845 } else {
11846 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011847 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011848 xmlXPathStepOpPtr exprOp;
11849 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11850 xmlNodePtr oldContextNode, contextNode = NULL;
11851 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011852 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011853
11854#ifdef LIBXML_XPTR_ENABLED
11855 /*
11856 * URGENT TODO: Check the following:
11857 * We don't expect location sets if evaluating prediates, right?
11858 * Only filters should expect location sets, right?
11859 */
11860#endif /* LIBXML_XPTR_ENABLED */
11861
11862 /*
11863 * Save old context.
11864 */
11865 oldContextNode = xpctxt->node;
11866 oldContextDoc = xpctxt->doc;
11867 /*
11868 * Get the expression of this predicate.
11869 */
11870 exprOp = &ctxt->comp->steps[op->ch2];
11871 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011872 xmlXPathObjectPtr tmp;
11873
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011874 if (set->nodeTab[i] == NULL)
11875 continue;
11876
11877 contextNode = set->nodeTab[i];
11878 xpctxt->node = contextNode;
11879 xpctxt->contextSize = contextSize;
11880 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011881
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011882 /*
11883 * Initialize the new set.
11884 * Also set the xpath document in case things like
11885 * key() evaluation are attempted on the predicate
11886 */
11887 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11888 (contextNode->doc != NULL))
11889 xpctxt->doc = contextNode->doc;
11890 /*
11891 * Evaluate the predicate expression with 1 context node
11892 * at a time; this node is packaged into a node set; this
11893 * node set is handed over to the evaluation mechanism.
11894 */
11895 if (contextObj == NULL)
11896 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011897 else {
11898 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11899 contextNode) < 0) {
11900 ctxt->error = XPATH_MEMORY_ERROR;
11901 goto evaluation_exit;
11902 }
11903 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011904
Daniel Veillardf5048b32011-08-18 17:10:13 +080011905 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011906 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011907 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011908 tmp = valuePop(ctxt);
11909 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011910
William M. Brackf1794562007-08-23 12:58:13 +000011911 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011912 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011913 /*
11914 * Free up the result
11915 * then pop off contextObj, which will be freed later
11916 */
11917 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011918 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011919 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011920 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011921 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011922 /* push the result back onto the stack */
11923 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011924
11925 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011926 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011927
11928 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011929 /*
11930 * Fits in the requested range.
11931 */
11932 newContextSize++;
11933 if (minPos == maxPos) {
11934 /*
11935 * Only 1 node was requested.
11936 */
11937 if (contextNode->type == XML_NAMESPACE_DECL) {
11938 /*
11939 * As always: take care of those nasty
11940 * namespace nodes.
11941 */
11942 set->nodeTab[i] = NULL;
11943 }
11944 xmlXPathNodeSetClear(set, hasNsNodes);
11945 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011946 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011947 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011948 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011949 if (pos == maxPos) {
11950 /*
11951 * We are done.
11952 */
11953 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11954 goto evaluation_exit;
11955 }
11956 } else {
11957 /*
11958 * Remove the entry from the initial node set.
11959 */
11960 set->nodeTab[i] = NULL;
11961 if (contextNode->type == XML_NAMESPACE_DECL)
11962 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11963 }
11964 if (exprRes != NULL) {
11965 xmlXPathReleaseObject(ctxt->context, exprRes);
11966 exprRes = NULL;
11967 }
11968 if (ctxt->value == contextObj) {
11969 /*
11970 * Don't free the temporary XPath object holding the
11971 * context node, in order to avoid massive recreation
11972 * inside this loop.
11973 */
11974 valuePop(ctxt);
11975 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11976 } else {
11977 /*
11978 * The object was lost in the evaluation machinery.
11979 * Can this happen? Maybe in case of internal-errors.
11980 */
11981 contextObj = NULL;
11982 }
11983 }
11984 goto evaluation_exit;
11985
11986evaluation_error:
11987 xmlXPathNodeSetClear(set, hasNsNodes);
11988 newContextSize = 0;
11989
11990evaluation_exit:
11991 if (contextObj != NULL) {
11992 if (ctxt->value == contextObj)
11993 valuePop(ctxt);
11994 xmlXPathReleaseObject(xpctxt, contextObj);
11995 }
11996 if (exprRes != NULL)
11997 xmlXPathReleaseObject(ctxt->context, exprRes);
11998 /*
11999 * Reset/invalidate the context.
12000 */
12001 xpctxt->node = oldContextNode;
12002 xpctxt->doc = oldContextDoc;
12003 xpctxt->contextSize = -1;
12004 xpctxt->proximityPosition = -1;
12005 return(newContextSize);
12006 }
12007 return(contextSize);
12008}
12009
12010static int
12011xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000012012 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012013 int *maxPos)
12014{
12015
12016 xmlXPathStepOpPtr exprOp;
12017
12018 /*
12019 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12020 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012021
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012022 /*
12023 * If not -1, then ch1 will point to:
12024 * 1) For predicates (XPATH_OP_PREDICATE):
12025 * - an inner predicate operator
12026 * 2) For filters (XPATH_OP_FILTER):
12027 * - an inner filter operater OR
12028 * - an expression selecting the node set.
12029 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012030 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012031 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12032 return(0);
12033
12034 if (op->ch2 != -1) {
12035 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012036 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012037 return(0);
12038
12039 if ((exprOp != NULL) &&
12040 (exprOp->op == XPATH_OP_VALUE) &&
12041 (exprOp->value4 != NULL) &&
12042 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12043 {
12044 /*
12045 * We have a "[n]" predicate here.
12046 * TODO: Unfortunately this simplistic test here is not
12047 * able to detect a position() predicate in compound
12048 * expressions like "[@attr = 'a" and position() = 1],
12049 * and even not the usage of position() in
12050 * "[position() = 1]"; thus - obviously - a position-range,
12051 * like it "[position() < 5]", is also not detected.
12052 * Maybe we could rewrite the AST to ease the optimization.
12053 */
12054 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012055
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012056 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12057 (float) *maxPos)
Daniel Veillard45490ae2008-07-29 09:13:19 +000012058 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012059 return(1);
12060 }
12061 }
12062 return(0);
12063}
12064
12065static int
12066xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12067 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012068 xmlNodePtr * first, xmlNodePtr * last,
12069 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012070{
12071
12072#define XP_TEST_HIT \
12073 if (hasAxisRange != 0) { \
12074 if (++pos == maxPos) { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012075 if (addNode(seq, cur) < 0) \
12076 ctxt->error = XPATH_MEMORY_ERROR; \
12077 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012078 } else { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012079 if (addNode(seq, cur) < 0) \
12080 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012081 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012082
12083#define XP_TEST_HIT_NS \
12084 if (hasAxisRange != 0) { \
12085 if (++pos == maxPos) { \
12086 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012087 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12088 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012089 goto axis_range_end; } \
12090 } else { \
12091 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012092 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) 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 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12097 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12098 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12099 const xmlChar *prefix = op->value4;
12100 const xmlChar *name = op->value5;
12101 const xmlChar *URI = NULL;
12102
12103#ifdef DEBUG_STEP
12104 int nbMatches = 0, prevMatches = 0;
12105#endif
12106 int total = 0, hasNsNodes = 0;
12107 /* The popped object holding the context nodes */
12108 xmlXPathObjectPtr obj;
12109 /* The set of context nodes for the node tests */
12110 xmlNodeSetPtr contextSeq;
12111 int contextIdx;
12112 xmlNodePtr contextNode;
12113 /* The context node for a compound traversal */
12114 xmlNodePtr outerContextNode;
12115 /* The final resulting node set wrt to all context nodes */
12116 xmlNodeSetPtr outSeq;
12117 /*
12118 * The temporary resulting node set wrt 1 context node.
12119 * Used to feed predicate evaluation.
12120 */
12121 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012122 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012123 /* First predicate operator */
12124 xmlXPathStepOpPtr predOp;
12125 int maxPos; /* The requested position() (when a "[n]" predicate) */
12126 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012127 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012128
12129 xmlXPathTraversalFunction next = NULL;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012130 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012131 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012132 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012133 xmlXPathContextPtr xpctxt = ctxt->context;
12134
12135
12136 CHECK_TYPE0(XPATH_NODESET);
12137 obj = valuePop(ctxt);
12138 /*
12139 * Setup namespaces.
12140 */
12141 if (prefix != NULL) {
12142 URI = xmlXPathNsLookup(xpctxt, prefix);
12143 if (URI == NULL) {
12144 xmlXPathReleaseObject(xpctxt, obj);
12145 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12146 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012147 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012148 /*
12149 * Setup axis.
12150 *
12151 * MAYBE FUTURE TODO: merging optimizations:
12152 * - If the nodes to be traversed wrt to the initial nodes and
12153 * the current axis cannot overlap, then we could avoid searching
12154 * for duplicates during the merge.
12155 * But the question is how/when to evaluate if they cannot overlap.
12156 * Example: if we know that for two initial nodes, the one is
12157 * not in the ancestor-or-self axis of the other, then we could safely
12158 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12159 * the descendant-or-self axis.
12160 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012161 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12162 switch (axis) {
12163 case AXIS_ANCESTOR:
12164 first = NULL;
12165 next = xmlXPathNextAncestor;
12166 break;
12167 case AXIS_ANCESTOR_OR_SELF:
12168 first = NULL;
12169 next = xmlXPathNextAncestorOrSelf;
12170 break;
12171 case AXIS_ATTRIBUTE:
12172 first = NULL;
12173 last = NULL;
12174 next = xmlXPathNextAttribute;
12175 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12176 break;
12177 case AXIS_CHILD:
12178 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012179 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12180 (type == NODE_TYPE_NODE))
12181 {
12182 /*
12183 * Optimization if an element node type is 'element'.
12184 */
12185 next = xmlXPathNextChildElement;
12186 } else
12187 next = xmlXPathNextChild;
12188 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12189 break;
12190 case AXIS_DESCENDANT:
12191 last = NULL;
12192 next = xmlXPathNextDescendant;
12193 break;
12194 case AXIS_DESCENDANT_OR_SELF:
12195 last = NULL;
12196 next = xmlXPathNextDescendantOrSelf;
12197 break;
12198 case AXIS_FOLLOWING:
12199 last = NULL;
12200 next = xmlXPathNextFollowing;
12201 break;
12202 case AXIS_FOLLOWING_SIBLING:
12203 last = NULL;
12204 next = xmlXPathNextFollowingSibling;
12205 break;
12206 case AXIS_NAMESPACE:
12207 first = NULL;
12208 last = NULL;
12209 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12210 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12211 break;
12212 case AXIS_PARENT:
12213 first = NULL;
12214 next = xmlXPathNextParent;
12215 break;
12216 case AXIS_PRECEDING:
12217 first = NULL;
12218 next = xmlXPathNextPrecedingInternal;
12219 break;
12220 case AXIS_PRECEDING_SIBLING:
12221 first = NULL;
12222 next = xmlXPathNextPrecedingSibling;
12223 break;
12224 case AXIS_SELF:
12225 first = NULL;
12226 last = NULL;
12227 next = xmlXPathNextSelf;
12228 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12229 break;
12230 }
12231
12232#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012233 xmlXPathDebugDumpStepAxis(op,
12234 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012235#endif
12236
12237 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012238 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012239 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012240 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012241 contextSeq = obj->nodesetval;
12242 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12243 xmlXPathReleaseObject(xpctxt, obj);
12244 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12245 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012246 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012247 /*
12248 * Predicate optimization ---------------------------------------------
12249 * If this step has a last predicate, which contains a position(),
12250 * then we'll optimize (although not exactly "position()", but only
12251 * the short-hand form, i.e., "[n]".
12252 *
12253 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012254 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012255 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12256 * ROOT -- op->ch1
12257 * PREDICATE -- op->ch2 (predOp)
12258 * PREDICATE -- predOp->ch1 = [parent::bar]
12259 * SORT
12260 * COLLECT 'parent' 'name' 'node' bar
12261 * NODE
12262 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12263 *
12264 */
12265 maxPos = 0;
12266 predOp = NULL;
12267 hasPredicateRange = 0;
12268 hasAxisRange = 0;
12269 if (op->ch2 != -1) {
12270 /*
12271 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12272 */
12273 predOp = &ctxt->comp->steps[op->ch2];
12274 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12275 if (predOp->ch1 != -1) {
12276 /*
12277 * Use the next inner predicate operator.
12278 */
12279 predOp = &ctxt->comp->steps[predOp->ch1];
12280 hasPredicateRange = 1;
12281 } else {
12282 /*
12283 * There's no other predicate than the [n] predicate.
12284 */
12285 predOp = NULL;
12286 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012287 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012288 }
12289 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012290 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012291 /*
12292 * Axis traversal -----------------------------------------------------
12293 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012294 /*
12295 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012296 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012297 * - For the namespace axis, the principal node type is namespace.
12298 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012299 *
12300 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012301 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012302 * select all element children of the context node
12303 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012304 oldContextNode = xpctxt->node;
12305 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012306 outSeq = NULL;
12307 seq = NULL;
12308 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012309 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012310 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012311
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012312
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012313 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12314 (ctxt->error == XPATH_EXPRESSION_OK)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012315 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012316
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012317 if (seq == NULL) {
12318 seq = xmlXPathNodeSetCreate(NULL);
12319 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012320 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012321 goto error;
12322 }
12323 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012324 /*
12325 * Traverse the axis and test the nodes.
12326 */
12327 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012328 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012329 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012330 do {
12331 cur = next(ctxt, cur);
12332 if (cur == NULL)
12333 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012334
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012335 /*
12336 * QUESTION TODO: What does the "first" and "last" stuff do?
12337 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012338 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012339 if (*first == cur)
12340 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012341 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012342#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012343 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012344#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012345 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012346#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012347 {
12348 break;
12349 }
12350 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012351 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012352 if (*last == cur)
12353 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012354 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012355#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012356 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012357#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012358 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012359#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012360 {
12361 break;
12362 }
12363 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012364
12365 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012366
Daniel Veillardf06307e2001-07-03 10:35:50 +000012367#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012368 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12369#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012370
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012371 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012372 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012373 total = 0;
12374 STRANGE
12375 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012376 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012377 /*
12378 * TODO: Don't we need to use
12379 * xmlXPathNodeSetAddNs() for namespace nodes here?
12380 * Surprisingly, some c14n tests fail, if we do this.
12381 */
12382 if (type == NODE_TYPE_NODE) {
12383 switch (cur->type) {
12384 case XML_DOCUMENT_NODE:
12385 case XML_HTML_DOCUMENT_NODE:
12386#ifdef LIBXML_DOCB_ENABLED
12387 case XML_DOCB_DOCUMENT_NODE:
12388#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012389 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012390 case XML_ATTRIBUTE_NODE:
12391 case XML_PI_NODE:
12392 case XML_COMMENT_NODE:
12393 case XML_CDATA_SECTION_NODE:
12394 case XML_TEXT_NODE:
12395 case XML_NAMESPACE_DECL:
12396 XP_TEST_HIT
12397 break;
12398 default:
12399 break;
12400 }
12401 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012402 if (type == XML_NAMESPACE_DECL)
12403 XP_TEST_HIT_NS
12404 else
12405 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012406 } else if ((type == NODE_TYPE_TEXT) &&
12407 (cur->type == XML_CDATA_SECTION_NODE))
12408 {
12409 XP_TEST_HIT
12410 }
12411 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012412 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012413 if ((cur->type == XML_PI_NODE) &&
12414 ((name == NULL) || xmlStrEqual(name, cur->name)))
12415 {
12416 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012417 }
12418 break;
12419 case NODE_TEST_ALL:
12420 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012421 if (cur->type == XML_ATTRIBUTE_NODE)
12422 {
12423 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012424 }
12425 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012426 if (cur->type == XML_NAMESPACE_DECL)
12427 {
12428 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012429 }
12430 } else {
12431 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012432 if (prefix == NULL)
12433 {
12434 XP_TEST_HIT
12435
Daniel Veillardf06307e2001-07-03 10:35:50 +000012436 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012437 (xmlStrEqual(URI, cur->ns->href)))
12438 {
12439 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012440 }
12441 }
12442 }
12443 break;
12444 case NODE_TEST_NS:{
12445 TODO;
12446 break;
12447 }
12448 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012449 if (axis == AXIS_ATTRIBUTE) {
12450 if (cur->type != XML_ATTRIBUTE_NODE)
12451 break;
12452 } else if (axis == AXIS_NAMESPACE) {
12453 if (cur->type != XML_NAMESPACE_DECL)
12454 break;
12455 } else {
12456 if (cur->type != XML_ELEMENT_NODE)
12457 break;
12458 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012459 switch (cur->type) {
12460 case XML_ELEMENT_NODE:
12461 if (xmlStrEqual(name, cur->name)) {
12462 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012463 if (cur->ns == NULL)
12464 {
12465 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012466 }
12467 } else {
12468 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012469 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012470 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012471 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012472 }
12473 }
12474 }
12475 break;
12476 case XML_ATTRIBUTE_NODE:{
12477 xmlAttrPtr attr = (xmlAttrPtr) cur;
12478
12479 if (xmlStrEqual(name, attr->name)) {
12480 if (prefix == NULL) {
12481 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012482 (attr->ns->prefix == NULL))
12483 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012484 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012485 }
12486 } else {
12487 if ((attr->ns != NULL) &&
12488 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012489 attr->ns->href)))
12490 {
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 }
12497 case XML_NAMESPACE_DECL:
12498 if (cur->type == XML_NAMESPACE_DECL) {
12499 xmlNsPtr ns = (xmlNsPtr) cur;
12500
12501 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012502 && (xmlStrEqual(ns->prefix, name)))
12503 {
12504 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012505 }
12506 }
12507 break;
12508 default:
12509 break;
12510 }
12511 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012512 } /* switch(test) */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012513 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012514
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012515 goto apply_predicates;
12516
Daniel Veillard45490ae2008-07-29 09:13:19 +000012517axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012518 /*
12519 * We have a "/foo[n]", and position() = n was reached.
12520 * Note that we can have as well "/foo/::parent::foo[1]", so
12521 * a duplicate-aware merge is still needed.
12522 * Merge with the result.
12523 */
12524 if (outSeq == NULL) {
12525 outSeq = seq;
12526 seq = NULL;
12527 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012528 outSeq = mergeAndClear(outSeq, seq, 0);
12529 /*
12530 * Break if only a true/false result was requested.
12531 */
12532 if (toBool)
12533 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012534 continue;
12535
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012536first_hit: /* ---------------------------------------------------------- */
12537 /*
12538 * Break if only a true/false result was requested and
12539 * no predicates existed and a node test succeeded.
12540 */
12541 if (outSeq == NULL) {
12542 outSeq = seq;
12543 seq = NULL;
12544 } else
12545 outSeq = mergeAndClear(outSeq, seq, 0);
12546 break;
12547
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012548#ifdef DEBUG_STEP
12549 if (seq != NULL)
12550 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012551#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012552
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012553apply_predicates: /* --------------------------------------------------- */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012554 if (ctxt->error != XPATH_EXPRESSION_OK)
12555 goto error;
12556
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012557 /*
12558 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012559 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012560 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12561 /*
12562 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012563 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012564 /*
12565 * QUESTION TODO: The old predicate evaluation took into
12566 * account location-sets.
12567 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12568 * Do we expect such a set here?
12569 * All what I learned now from the evaluation semantics
12570 * does not indicate that a location-set will be processed
12571 * here, so this looks OK.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012572 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012573 /*
12574 * Iterate over all predicates, starting with the outermost
12575 * predicate.
12576 * TODO: Problem: we cannot execute the inner predicates first
12577 * since we cannot go back *up* the operator tree!
12578 * Options we have:
12579 * 1) Use of recursive functions (like is it currently done
12580 * via xmlXPathCompOpEval())
12581 * 2) Add a predicate evaluation information stack to the
12582 * context struct
12583 * 3) Change the way the operators are linked; we need a
12584 * "parent" field on xmlXPathStepOp
12585 *
12586 * For the moment, I'll try to solve this with a recursive
12587 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012588 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012589 size = seq->nodeNr;
12590 if (hasPredicateRange != 0)
12591 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12592 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12593 else
12594 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12595 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012596
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012597 if (ctxt->error != XPATH_EXPRESSION_OK) {
12598 total = 0;
12599 goto error;
12600 }
12601 /*
12602 * Add the filtered set of nodes to the result node set.
12603 */
12604 if (newSize == 0) {
12605 /*
12606 * The predicates filtered all nodes out.
12607 */
12608 xmlXPathNodeSetClear(seq, hasNsNodes);
12609 } else if (seq->nodeNr > 0) {
12610 /*
12611 * Add to result set.
12612 */
12613 if (outSeq == NULL) {
12614 if (size != newSize) {
12615 /*
12616 * We need to merge and clear here, since
12617 * the sequence will contained NULLed entries.
12618 */
12619 outSeq = mergeAndClear(NULL, seq, 1);
12620 } else {
12621 outSeq = seq;
12622 seq = NULL;
12623 }
12624 } else
12625 outSeq = mergeAndClear(outSeq, seq,
12626 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012627 /*
12628 * Break if only a true/false result was requested.
12629 */
12630 if (toBool)
12631 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012632 }
12633 } else if (seq->nodeNr > 0) {
12634 /*
12635 * Add to result set.
12636 */
12637 if (outSeq == NULL) {
12638 outSeq = seq;
12639 seq = NULL;
12640 } else {
12641 outSeq = mergeAndClear(outSeq, seq, 0);
12642 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012643 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012644 }
12645
12646error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012647 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012648 /*
12649 * QUESTION TODO: What does this do and why?
12650 * TODO: Do we have to do this also for the "error"
12651 * cleanup further down?
12652 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012653 ctxt->value->boolval = 1;
12654 ctxt->value->user = obj->user;
12655 obj->user = NULL;
12656 obj->boolval = 0;
12657 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012658 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012659
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012660 /*
12661 * Ensure we return at least an emtpy set.
12662 */
12663 if (outSeq == NULL) {
12664 if ((seq != NULL) && (seq->nodeNr == 0))
12665 outSeq = seq;
12666 else
12667 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012668 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012669 }
12670 if ((seq != NULL) && (seq != outSeq)) {
12671 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012672 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012673 /*
12674 * Hand over the result. Better to push the set also in
12675 * case of errors.
12676 */
12677 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12678 /*
12679 * Reset the context node.
12680 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012681 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012682
12683#ifdef DEBUG_STEP
12684 xmlGenericError(xmlGenericErrorContext,
12685 "\nExamined %d nodes, found %d nodes at that step\n",
12686 total, nbMatches);
12687#endif
12688
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012689 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012690}
12691
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012692static int
12693xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12694 xmlXPathStepOpPtr op, xmlNodePtr * first);
12695
Daniel Veillardf06307e2001-07-03 10:35:50 +000012696/**
12697 * xmlXPathCompOpEvalFirst:
12698 * @ctxt: the XPath parser context with the compiled expression
12699 * @op: an XPath compiled operation
12700 * @first: the first elem found so far
12701 *
12702 * Evaluate the Precompiled XPath operation searching only the first
12703 * element in document order
12704 *
12705 * Returns the number of examined objects.
12706 */
12707static int
12708xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12709 xmlXPathStepOpPtr op, xmlNodePtr * first)
12710{
12711 int total = 0, cur;
12712 xmlXPathCompExprPtr comp;
12713 xmlXPathObjectPtr arg1, arg2;
12714
Daniel Veillard556c6682001-10-06 09:59:51 +000012715 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012716 comp = ctxt->comp;
12717 switch (op->op) {
12718 case XPATH_OP_END:
12719 return (0);
12720 case XPATH_OP_UNION:
12721 total =
12722 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12723 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012724 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012725 if ((ctxt->value != NULL)
12726 && (ctxt->value->type == XPATH_NODESET)
12727 && (ctxt->value->nodesetval != NULL)
12728 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12729 /*
12730 * limit tree traversing to first node in the result
12731 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012732 /*
12733 * OPTIMIZE TODO: This implicitely sorts
12734 * the result, even if not needed. E.g. if the argument
12735 * of the count() function, no sorting is needed.
12736 * OPTIMIZE TODO: How do we know if the node-list wasn't
12737 * aready sorted?
12738 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012739 if (ctxt->value->nodesetval->nodeNr > 1)
12740 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012741 *first = ctxt->value->nodesetval->nodeTab[0];
12742 }
12743 cur =
12744 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12745 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012746 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012747 CHECK_TYPE0(XPATH_NODESET);
12748 arg2 = valuePop(ctxt);
12749
12750 CHECK_TYPE0(XPATH_NODESET);
12751 arg1 = valuePop(ctxt);
12752
12753 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12754 arg2->nodesetval);
12755 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012756 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012757 /* optimizer */
12758 if (total > cur)
12759 xmlXPathCompSwap(op);
12760 return (total + cur);
12761 case XPATH_OP_ROOT:
12762 xmlXPathRoot(ctxt);
12763 return (0);
12764 case XPATH_OP_NODE:
12765 if (op->ch1 != -1)
12766 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012767 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012768 if (op->ch2 != -1)
12769 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012770 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012771 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12772 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012773 return (total);
12774 case XPATH_OP_RESET:
12775 if (op->ch1 != -1)
12776 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012777 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012778 if (op->ch2 != -1)
12779 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012780 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012781 ctxt->context->node = NULL;
12782 return (total);
12783 case XPATH_OP_COLLECT:{
12784 if (op->ch1 == -1)
12785 return (total);
12786
12787 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012788 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012789
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012790 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012791 return (total);
12792 }
12793 case XPATH_OP_VALUE:
12794 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012795 xmlXPathCacheObjectCopy(ctxt->context,
12796 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012797 return (0);
12798 case XPATH_OP_SORT:
12799 if (op->ch1 != -1)
12800 total +=
12801 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12802 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012803 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012804 if ((ctxt->value != NULL)
12805 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012806 && (ctxt->value->nodesetval != NULL)
12807 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012808 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12809 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012810#ifdef XP_OPTIMIZED_FILTER_FIRST
12811 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012812 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012813 return (total);
12814#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012815 default:
12816 return (xmlXPathCompOpEval(ctxt, op));
12817 }
12818}
12819
12820/**
12821 * xmlXPathCompOpEvalLast:
12822 * @ctxt: the XPath parser context with the compiled expression
12823 * @op: an XPath compiled operation
12824 * @last: the last elem found so far
12825 *
12826 * Evaluate the Precompiled XPath operation searching only the last
12827 * element in document order
12828 *
William M. Brack08171912003-12-29 02:52:11 +000012829 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012830 */
12831static int
12832xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12833 xmlNodePtr * last)
12834{
12835 int total = 0, cur;
12836 xmlXPathCompExprPtr comp;
12837 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012838 xmlNodePtr bak;
12839 xmlDocPtr bakd;
12840 int pp;
12841 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012842
Daniel Veillard556c6682001-10-06 09:59:51 +000012843 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012844 comp = ctxt->comp;
12845 switch (op->op) {
12846 case XPATH_OP_END:
12847 return (0);
12848 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012849 bakd = ctxt->context->doc;
12850 bak = ctxt->context->node;
12851 pp = ctxt->context->proximityPosition;
12852 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012853 total =
12854 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012855 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012856 if ((ctxt->value != NULL)
12857 && (ctxt->value->type == XPATH_NODESET)
12858 && (ctxt->value->nodesetval != NULL)
12859 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12860 /*
12861 * limit tree traversing to first node in the result
12862 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012863 if (ctxt->value->nodesetval->nodeNr > 1)
12864 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012865 *last =
12866 ctxt->value->nodesetval->nodeTab[ctxt->value->
12867 nodesetval->nodeNr -
12868 1];
12869 }
William M. Brackce4fc562004-01-22 02:47:18 +000012870 ctxt->context->doc = bakd;
12871 ctxt->context->node = bak;
12872 ctxt->context->proximityPosition = pp;
12873 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012874 cur =
12875 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012876 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012877 if ((ctxt->value != NULL)
12878 && (ctxt->value->type == XPATH_NODESET)
12879 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012880 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012881 }
12882 CHECK_TYPE0(XPATH_NODESET);
12883 arg2 = valuePop(ctxt);
12884
12885 CHECK_TYPE0(XPATH_NODESET);
12886 arg1 = valuePop(ctxt);
12887
12888 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12889 arg2->nodesetval);
12890 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012891 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012892 /* optimizer */
12893 if (total > cur)
12894 xmlXPathCompSwap(op);
12895 return (total + cur);
12896 case XPATH_OP_ROOT:
12897 xmlXPathRoot(ctxt);
12898 return (0);
12899 case XPATH_OP_NODE:
12900 if (op->ch1 != -1)
12901 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012902 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012903 if (op->ch2 != -1)
12904 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012905 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012906 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12907 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012908 return (total);
12909 case XPATH_OP_RESET:
12910 if (op->ch1 != -1)
12911 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012912 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012913 if (op->ch2 != -1)
12914 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012915 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012916 ctxt->context->node = NULL;
12917 return (total);
12918 case XPATH_OP_COLLECT:{
12919 if (op->ch1 == -1)
12920 return (0);
12921
12922 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012923 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012924
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012925 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012926 return (total);
12927 }
12928 case XPATH_OP_VALUE:
12929 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012930 xmlXPathCacheObjectCopy(ctxt->context,
12931 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012932 return (0);
12933 case XPATH_OP_SORT:
12934 if (op->ch1 != -1)
12935 total +=
12936 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12937 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012938 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012939 if ((ctxt->value != NULL)
12940 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012941 && (ctxt->value->nodesetval != NULL)
12942 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012943 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12944 return (total);
12945 default:
12946 return (xmlXPathCompOpEval(ctxt, op));
12947 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012948}
12949
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012950#ifdef XP_OPTIMIZED_FILTER_FIRST
12951static int
12952xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12953 xmlXPathStepOpPtr op, xmlNodePtr * first)
12954{
12955 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012956 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012957 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012958 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012959 xmlNodeSetPtr oldset;
12960 xmlNodePtr oldnode;
12961 xmlDocPtr oldDoc;
12962 int i;
12963
12964 CHECK_ERROR0;
12965 comp = ctxt->comp;
12966 /*
12967 * Optimization for ()[last()] selection i.e. the last elem
12968 */
12969 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12970 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12971 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12972 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012973
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012974 if ((f != -1) &&
12975 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12976 (comp->steps[f].value5 == NULL) &&
12977 (comp->steps[f].value == 0) &&
12978 (comp->steps[f].value4 != NULL) &&
12979 (xmlStrEqual
12980 (comp->steps[f].value4, BAD_CAST "last"))) {
12981 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012982
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012983 total +=
12984 xmlXPathCompOpEvalLast(ctxt,
12985 &comp->steps[op->ch1],
12986 &last);
12987 CHECK_ERROR0;
12988 /*
12989 * The nodeset should be in document order,
12990 * Keep only the last value
12991 */
12992 if ((ctxt->value != NULL) &&
12993 (ctxt->value->type == XPATH_NODESET) &&
12994 (ctxt->value->nodesetval != NULL) &&
12995 (ctxt->value->nodesetval->nodeTab != NULL) &&
12996 (ctxt->value->nodesetval->nodeNr > 1)) {
12997 ctxt->value->nodesetval->nodeTab[0] =
12998 ctxt->value->nodesetval->nodeTab[ctxt->
12999 value->
13000 nodesetval->
13001 nodeNr -
13002 1];
13003 ctxt->value->nodesetval->nodeNr = 1;
13004 *first = *(ctxt->value->nodesetval->nodeTab);
13005 }
13006 return (total);
13007 }
13008 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013009
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013010 if (op->ch1 != -1)
13011 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13012 CHECK_ERROR0;
13013 if (op->ch2 == -1)
13014 return (total);
13015 if (ctxt->value == NULL)
13016 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013017
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013018#ifdef LIBXML_XPTR_ENABLED
13019 oldnode = ctxt->context->node;
13020 /*
13021 * Hum are we filtering the result of an XPointer expression
13022 */
13023 if (ctxt->value->type == XPATH_LOCATIONSET) {
13024 xmlXPathObjectPtr tmp = NULL;
13025 xmlLocationSetPtr newlocset = NULL;
13026 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013027
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013028 /*
13029 * Extract the old locset, and then evaluate the result of the
13030 * expression for all the element in the locset. use it to grow
13031 * up a new locset.
13032 */
13033 CHECK_TYPE0(XPATH_LOCATIONSET);
13034 obj = valuePop(ctxt);
13035 oldlocset = obj->user;
13036 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013037
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013038 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13039 ctxt->context->contextSize = 0;
13040 ctxt->context->proximityPosition = 0;
13041 if (op->ch2 != -1)
13042 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13043 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013044 if (res != NULL) {
13045 xmlXPathReleaseObject(ctxt->context, res);
13046 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013047 valuePush(ctxt, obj);
13048 CHECK_ERROR0;
13049 return (total);
13050 }
13051 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013052
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013053 for (i = 0; i < oldlocset->locNr; i++) {
13054 /*
13055 * Run the evaluation with a node list made of a
13056 * single item in the nodelocset.
13057 */
13058 ctxt->context->node = oldlocset->locTab[i]->user;
13059 ctxt->context->contextSize = oldlocset->locNr;
13060 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013061 if (tmp == NULL) {
13062 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13063 ctxt->context->node);
13064 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013065 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13066 ctxt->context->node) < 0) {
13067 ctxt->error = XPATH_MEMORY_ERROR;
13068 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013069 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013070 valuePush(ctxt, tmp);
13071 if (op->ch2 != -1)
13072 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13073 if (ctxt->error != XPATH_EXPRESSION_OK) {
13074 xmlXPathFreeObject(obj);
13075 return(0);
13076 }
13077 /*
13078 * The result of the evaluation need to be tested to
13079 * decided whether the filter succeeded or not
13080 */
13081 res = valuePop(ctxt);
13082 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13083 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013084 xmlXPathCacheObjectCopy(ctxt->context,
13085 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013086 }
13087 /*
13088 * Cleanup
13089 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013090 if (res != NULL) {
13091 xmlXPathReleaseObject(ctxt->context, res);
13092 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013093 if (ctxt->value == tmp) {
13094 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013095 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013096 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013097 * REVISIT TODO: Don't create a temporary nodeset
13098 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013099 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013100 /* OLD: xmlXPathFreeObject(res); */
13101 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013102 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013103 ctxt->context->node = NULL;
13104 /*
13105 * Only put the first node in the result, then leave.
13106 */
13107 if (newlocset->locNr > 0) {
13108 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13109 break;
13110 }
13111 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013112 if (tmp != NULL) {
13113 xmlXPathReleaseObject(ctxt->context, tmp);
13114 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013115 /*
13116 * The result is used as the new evaluation locset.
13117 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013118 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013119 ctxt->context->node = NULL;
13120 ctxt->context->contextSize = -1;
13121 ctxt->context->proximityPosition = -1;
13122 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13123 ctxt->context->node = oldnode;
13124 return (total);
13125 }
13126#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013127
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013128 /*
13129 * Extract the old set, and then evaluate the result of the
13130 * expression for all the element in the set. use it to grow
13131 * up a new set.
13132 */
13133 CHECK_TYPE0(XPATH_NODESET);
13134 obj = valuePop(ctxt);
13135 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013136
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013137 oldnode = ctxt->context->node;
13138 oldDoc = ctxt->context->doc;
13139 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013140
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013141 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13142 ctxt->context->contextSize = 0;
13143 ctxt->context->proximityPosition = 0;
13144 /* QUESTION TODO: Why was this code commented out?
13145 if (op->ch2 != -1)
13146 total +=
13147 xmlXPathCompOpEval(ctxt,
13148 &comp->steps[op->ch2]);
13149 CHECK_ERROR0;
13150 res = valuePop(ctxt);
13151 if (res != NULL)
13152 xmlXPathFreeObject(res);
13153 */
13154 valuePush(ctxt, obj);
13155 ctxt->context->node = oldnode;
13156 CHECK_ERROR0;
13157 } else {
13158 xmlNodeSetPtr newset;
13159 xmlXPathObjectPtr tmp = NULL;
13160 /*
13161 * Initialize the new set.
13162 * Also set the xpath document in case things like
13163 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013164 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013165 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013166 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013167
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013168 for (i = 0; i < oldset->nodeNr; i++) {
13169 /*
13170 * Run the evaluation with a node list made of
13171 * a single item in the nodeset.
13172 */
13173 ctxt->context->node = oldset->nodeTab[i];
13174 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13175 (oldset->nodeTab[i]->doc != NULL))
13176 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013177 if (tmp == NULL) {
13178 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13179 ctxt->context->node);
13180 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013181 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13182 ctxt->context->node) < 0) {
13183 ctxt->error = XPATH_MEMORY_ERROR;
13184 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013185 }
13186 valuePush(ctxt, tmp);
13187 ctxt->context->contextSize = oldset->nodeNr;
13188 ctxt->context->proximityPosition = i + 1;
13189 if (op->ch2 != -1)
13190 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13191 if (ctxt->error != XPATH_EXPRESSION_OK) {
13192 xmlXPathFreeNodeSet(newset);
13193 xmlXPathFreeObject(obj);
13194 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013195 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013196 /*
13197 * The result of the evaluation needs to be tested to
13198 * decide whether the filter succeeded or not
13199 */
13200 res = valuePop(ctxt);
13201 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013202 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13203 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013204 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013205 /*
13206 * Cleanup
13207 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013208 if (res != NULL) {
13209 xmlXPathReleaseObject(ctxt->context, res);
13210 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013211 if (ctxt->value == tmp) {
13212 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013213 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013214 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013215 * in order to avoid massive recreation inside this
13216 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013217 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013218 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013219 } else
13220 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013221 ctxt->context->node = NULL;
13222 /*
13223 * Only put the first node in the result, then leave.
13224 */
13225 if (newset->nodeNr > 0) {
13226 *first = *(newset->nodeTab);
13227 break;
13228 }
13229 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013230 if (tmp != NULL) {
13231 xmlXPathReleaseObject(ctxt->context, tmp);
13232 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013233 /*
13234 * The result is used as the new evaluation set.
13235 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013236 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013237 ctxt->context->node = NULL;
13238 ctxt->context->contextSize = -1;
13239 ctxt->context->proximityPosition = -1;
13240 /* may want to move this past the '}' later */
13241 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013242 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013243 }
13244 ctxt->context->node = oldnode;
13245 return(total);
13246}
13247#endif /* XP_OPTIMIZED_FILTER_FIRST */
13248
Owen Taylor3473f882001-02-23 17:55:21 +000013249/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013250 * xmlXPathCompOpEval:
13251 * @ctxt: the XPath parser context with the compiled expression
13252 * @op: an XPath compiled operation
13253 *
13254 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013255 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013256 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013257static int
13258xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13259{
13260 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013261 int equal, ret;
13262 xmlXPathCompExprPtr comp;
13263 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013264 xmlNodePtr bak;
13265 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013266 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013267 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013268
Daniel Veillard556c6682001-10-06 09:59:51 +000013269 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013270 comp = ctxt->comp;
13271 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013272 case XPATH_OP_END:
13273 return (0);
13274 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013275 bakd = ctxt->context->doc;
13276 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013277 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013278 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013279 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013280 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013281 xmlXPathBooleanFunction(ctxt, 1);
13282 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13283 return (total);
13284 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013285 ctxt->context->doc = bakd;
13286 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013287 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013288 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013289 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013290 if (ctxt->error) {
13291 xmlXPathFreeObject(arg2);
13292 return(0);
13293 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013294 xmlXPathBooleanFunction(ctxt, 1);
13295 arg1 = valuePop(ctxt);
13296 arg1->boolval &= arg2->boolval;
13297 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013298 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013299 return (total);
13300 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013301 bakd = ctxt->context->doc;
13302 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013303 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013304 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013305 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013306 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013307 xmlXPathBooleanFunction(ctxt, 1);
13308 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13309 return (total);
13310 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013311 ctxt->context->doc = bakd;
13312 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013313 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013314 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013315 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013316 if (ctxt->error) {
13317 xmlXPathFreeObject(arg2);
13318 return(0);
13319 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013320 xmlXPathBooleanFunction(ctxt, 1);
13321 arg1 = valuePop(ctxt);
13322 arg1->boolval |= arg2->boolval;
13323 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013324 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013325 return (total);
13326 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013327 bakd = ctxt->context->doc;
13328 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013329 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013330 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013331 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013332 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013333 ctxt->context->doc = bakd;
13334 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013335 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013336 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013337 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013338 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013339 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013340 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013341 else
13342 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013343 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013344 return (total);
13345 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013346 bakd = ctxt->context->doc;
13347 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013348 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013349 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013350 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013351 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013352 ctxt->context->doc = bakd;
13353 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013354 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013355 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013356 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013357 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013358 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013359 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013360 return (total);
13361 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013362 bakd = ctxt->context->doc;
13363 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013364 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013365 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013366 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013367 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013368 if (op->ch2 != -1) {
13369 ctxt->context->doc = bakd;
13370 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013371 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013372 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013373 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013374 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013375 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013376 if (op->value == 0)
13377 xmlXPathSubValues(ctxt);
13378 else if (op->value == 1)
13379 xmlXPathAddValues(ctxt);
13380 else if (op->value == 2)
13381 xmlXPathValueFlipSign(ctxt);
13382 else if (op->value == 3) {
13383 CAST_TO_NUMBER;
13384 CHECK_TYPE0(XPATH_NUMBER);
13385 }
13386 return (total);
13387 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013388 bakd = ctxt->context->doc;
13389 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013390 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013391 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013392 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013393 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013394 ctxt->context->doc = bakd;
13395 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013396 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013397 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013398 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013399 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013400 if (op->value == 0)
13401 xmlXPathMultValues(ctxt);
13402 else if (op->value == 1)
13403 xmlXPathDivValues(ctxt);
13404 else if (op->value == 2)
13405 xmlXPathModValues(ctxt);
13406 return (total);
13407 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013408 bakd = ctxt->context->doc;
13409 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013410 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013411 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013412 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013413 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013414 ctxt->context->doc = bakd;
13415 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013416 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013417 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013418 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013419 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013420 CHECK_TYPE0(XPATH_NODESET);
13421 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013422
Daniel Veillardf06307e2001-07-03 10:35:50 +000013423 CHECK_TYPE0(XPATH_NODESET);
13424 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013425
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013426 if ((arg1->nodesetval == NULL) ||
13427 ((arg2->nodesetval != NULL) &&
13428 (arg2->nodesetval->nodeNr != 0)))
13429 {
13430 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13431 arg2->nodesetval);
13432 }
13433
Daniel Veillardf06307e2001-07-03 10:35:50 +000013434 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013435 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013436 return (total);
13437 case XPATH_OP_ROOT:
13438 xmlXPathRoot(ctxt);
13439 return (total);
13440 case XPATH_OP_NODE:
13441 if (op->ch1 != -1)
13442 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013443 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013444 if (op->ch2 != -1)
13445 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013446 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013447 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13448 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013449 return (total);
13450 case XPATH_OP_RESET:
13451 if (op->ch1 != -1)
13452 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013453 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013454 if (op->ch2 != -1)
13455 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013456 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013457 ctxt->context->node = NULL;
13458 return (total);
13459 case XPATH_OP_COLLECT:{
13460 if (op->ch1 == -1)
13461 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013462
Daniel Veillardf06307e2001-07-03 10:35:50 +000013463 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013464 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013465
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013466 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013467 return (total);
13468 }
13469 case XPATH_OP_VALUE:
13470 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013471 xmlXPathCacheObjectCopy(ctxt->context,
13472 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013473 return (total);
13474 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013475 xmlXPathObjectPtr val;
13476
Daniel Veillardf06307e2001-07-03 10:35:50 +000013477 if (op->ch1 != -1)
13478 total +=
13479 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013480 if (op->value5 == NULL) {
13481 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13482 if (val == NULL) {
13483 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13484 return(0);
13485 }
13486 valuePush(ctxt, val);
13487 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013488 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013489
Daniel Veillardf06307e2001-07-03 10:35:50 +000013490 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13491 if (URI == NULL) {
13492 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013493 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13494 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013495 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013496 return (total);
13497 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013498 val = xmlXPathVariableLookupNS(ctxt->context,
13499 op->value4, URI);
13500 if (val == NULL) {
13501 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13502 return(0);
13503 }
13504 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013505 }
13506 return (total);
13507 }
13508 case XPATH_OP_FUNCTION:{
13509 xmlXPathFunction func;
13510 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013511 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013512 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013513
Daniel Veillardf5048b32011-08-18 17:10:13 +080013514 frame = xmlXPathSetFrame(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013515 if (op->ch1 != -1)
13516 total +=
13517 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013518 if (ctxt->valueNr < op->value) {
13519 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013520 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013521 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013522 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013523 return (total);
13524 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013525 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013526 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13527 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013528 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013529 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013530 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013531 return (total);
13532 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013533 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013534 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013535 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013536 else {
13537 const xmlChar *URI = NULL;
13538
13539 if (op->value5 == NULL)
13540 func =
13541 xmlXPathFunctionLookup(ctxt->context,
13542 op->value4);
13543 else {
13544 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13545 if (URI == NULL) {
13546 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013547 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13548 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013549 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013550 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013551 return (total);
13552 }
13553 func = xmlXPathFunctionLookupNS(ctxt->context,
13554 op->value4, URI);
13555 }
13556 if (func == NULL) {
13557 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013558 "xmlXPathCompOpEval: function %s not found\n",
13559 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013560 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013561 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013562 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013563 op->cacheURI = (void *) URI;
13564 }
13565 oldFunc = ctxt->context->function;
13566 oldFuncURI = ctxt->context->functionURI;
13567 ctxt->context->function = op->value4;
13568 ctxt->context->functionURI = op->cacheURI;
13569 func(ctxt, op->value);
13570 ctxt->context->function = oldFunc;
13571 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013572 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013573 return (total);
13574 }
13575 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013576 bakd = ctxt->context->doc;
13577 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013578 pp = ctxt->context->proximityPosition;
13579 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013580 if (op->ch1 != -1)
13581 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013582 ctxt->context->contextSize = cs;
13583 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013584 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013585 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013586 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013587 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013588 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013589 ctxt->context->doc = bakd;
13590 ctxt->context->node = bak;
13591 CHECK_ERROR0;
13592 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013593 return (total);
13594 case XPATH_OP_PREDICATE:
13595 case XPATH_OP_FILTER:{
13596 xmlXPathObjectPtr res;
13597 xmlXPathObjectPtr obj, tmp;
13598 xmlNodeSetPtr newset = NULL;
13599 xmlNodeSetPtr oldset;
13600 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013601 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013602 int i;
13603
13604 /*
13605 * Optimization for ()[1] selection i.e. the first elem
13606 */
13607 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013608#ifdef XP_OPTIMIZED_FILTER_FIRST
13609 /*
13610 * FILTER TODO: Can we assume that the inner processing
13611 * will result in an ordered list if we have an
13612 * XPATH_OP_FILTER?
13613 * What about an additional field or flag on
13614 * xmlXPathObject like @sorted ? This way we wouln'd need
13615 * to assume anything, so it would be more robust and
13616 * easier to optimize.
13617 */
13618 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13619 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13620#else
13621 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13622#endif
13623 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013624 xmlXPathObjectPtr val;
13625
13626 val = comp->steps[op->ch2].value4;
13627 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13628 (val->floatval == 1.0)) {
13629 xmlNodePtr first = NULL;
13630
13631 total +=
13632 xmlXPathCompOpEvalFirst(ctxt,
13633 &comp->steps[op->ch1],
13634 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013635 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013636 /*
13637 * The nodeset should be in document order,
13638 * Keep only the first value
13639 */
13640 if ((ctxt->value != NULL) &&
13641 (ctxt->value->type == XPATH_NODESET) &&
13642 (ctxt->value->nodesetval != NULL) &&
13643 (ctxt->value->nodesetval->nodeNr > 1))
13644 ctxt->value->nodesetval->nodeNr = 1;
13645 return (total);
13646 }
13647 }
13648 /*
13649 * Optimization for ()[last()] selection i.e. the last elem
13650 */
13651 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13652 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13653 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13654 int f = comp->steps[op->ch2].ch1;
13655
13656 if ((f != -1) &&
13657 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13658 (comp->steps[f].value5 == NULL) &&
13659 (comp->steps[f].value == 0) &&
13660 (comp->steps[f].value4 != NULL) &&
13661 (xmlStrEqual
13662 (comp->steps[f].value4, BAD_CAST "last"))) {
13663 xmlNodePtr last = NULL;
13664
13665 total +=
13666 xmlXPathCompOpEvalLast(ctxt,
13667 &comp->steps[op->ch1],
13668 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013669 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013670 /*
13671 * The nodeset should be in document order,
13672 * Keep only the last value
13673 */
13674 if ((ctxt->value != NULL) &&
13675 (ctxt->value->type == XPATH_NODESET) &&
13676 (ctxt->value->nodesetval != NULL) &&
13677 (ctxt->value->nodesetval->nodeTab != NULL) &&
13678 (ctxt->value->nodesetval->nodeNr > 1)) {
13679 ctxt->value->nodesetval->nodeTab[0] =
13680 ctxt->value->nodesetval->nodeTab[ctxt->
13681 value->
13682 nodesetval->
13683 nodeNr -
13684 1];
13685 ctxt->value->nodesetval->nodeNr = 1;
13686 }
13687 return (total);
13688 }
13689 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013690 /*
13691 * Process inner predicates first.
13692 * Example "index[parent::book][1]":
13693 * ...
13694 * PREDICATE <-- we are here "[1]"
13695 * PREDICATE <-- process "[parent::book]" first
13696 * SORT
13697 * COLLECT 'parent' 'name' 'node' book
13698 * NODE
13699 * ELEM Object is a number : 1
13700 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013701 if (op->ch1 != -1)
13702 total +=
13703 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013704 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013705 if (op->ch2 == -1)
13706 return (total);
13707 if (ctxt->value == NULL)
13708 return (total);
13709
13710 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013711
13712#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013713 /*
13714 * Hum are we filtering the result of an XPointer expression
13715 */
13716 if (ctxt->value->type == XPATH_LOCATIONSET) {
13717 xmlLocationSetPtr newlocset = NULL;
13718 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013719
Daniel Veillardf06307e2001-07-03 10:35:50 +000013720 /*
13721 * Extract the old locset, and then evaluate the result of the
13722 * expression for all the element in the locset. use it to grow
13723 * up a new locset.
13724 */
13725 CHECK_TYPE0(XPATH_LOCATIONSET);
13726 obj = valuePop(ctxt);
13727 oldlocset = obj->user;
13728 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013729
Daniel Veillardf06307e2001-07-03 10:35:50 +000013730 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13731 ctxt->context->contextSize = 0;
13732 ctxt->context->proximityPosition = 0;
13733 if (op->ch2 != -1)
13734 total +=
13735 xmlXPathCompOpEval(ctxt,
13736 &comp->steps[op->ch2]);
13737 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013738 if (res != NULL) {
13739 xmlXPathReleaseObject(ctxt->context, res);
13740 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013741 valuePush(ctxt, obj);
13742 CHECK_ERROR0;
13743 return (total);
13744 }
13745 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013746
Daniel Veillardf06307e2001-07-03 10:35:50 +000013747 for (i = 0; i < oldlocset->locNr; i++) {
13748 /*
13749 * Run the evaluation with a node list made of a
13750 * single item in the nodelocset.
13751 */
13752 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013753 ctxt->context->contextSize = oldlocset->locNr;
13754 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013755 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13756 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013757 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013758
Daniel Veillardf06307e2001-07-03 10:35:50 +000013759 if (op->ch2 != -1)
13760 total +=
13761 xmlXPathCompOpEval(ctxt,
13762 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013763 if (ctxt->error != XPATH_EXPRESSION_OK) {
13764 xmlXPathFreeObject(obj);
13765 return(0);
13766 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013767
Daniel Veillardf06307e2001-07-03 10:35:50 +000013768 /*
13769 * The result of the evaluation need to be tested to
13770 * decided whether the filter succeeded or not
13771 */
13772 res = valuePop(ctxt);
13773 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13774 xmlXPtrLocationSetAdd(newlocset,
13775 xmlXPathObjectCopy
13776 (oldlocset->locTab[i]));
13777 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013778
Daniel Veillardf06307e2001-07-03 10:35:50 +000013779 /*
13780 * Cleanup
13781 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013782 if (res != NULL) {
13783 xmlXPathReleaseObject(ctxt->context, res);
13784 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013785 if (ctxt->value == tmp) {
13786 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013787 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013788 }
13789
13790 ctxt->context->node = NULL;
13791 }
13792
13793 /*
13794 * The result is used as the new evaluation locset.
13795 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013796 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013797 ctxt->context->node = NULL;
13798 ctxt->context->contextSize = -1;
13799 ctxt->context->proximityPosition = -1;
13800 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13801 ctxt->context->node = oldnode;
13802 return (total);
13803 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013804#endif /* LIBXML_XPTR_ENABLED */
13805
Daniel Veillardf06307e2001-07-03 10:35:50 +000013806 /*
13807 * Extract the old set, and then evaluate the result of the
13808 * expression for all the element in the set. use it to grow
13809 * up a new set.
13810 */
13811 CHECK_TYPE0(XPATH_NODESET);
13812 obj = valuePop(ctxt);
13813 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013814
Daniel Veillardf06307e2001-07-03 10:35:50 +000013815 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013816 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013817 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013818
Daniel Veillardf06307e2001-07-03 10:35:50 +000013819 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13820 ctxt->context->contextSize = 0;
13821 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013822/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013823 if (op->ch2 != -1)
13824 total +=
13825 xmlXPathCompOpEval(ctxt,
13826 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013827 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013828 res = valuePop(ctxt);
13829 if (res != NULL)
13830 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013831*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013832 valuePush(ctxt, obj);
13833 ctxt->context->node = oldnode;
13834 CHECK_ERROR0;
13835 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013836 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013837 /*
13838 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013839 * Also set the xpath document in case things like
13840 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013841 */
13842 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013843 /*
13844 * SPEC XPath 1.0:
13845 * "For each node in the node-set to be filtered, the
13846 * PredicateExpr is evaluated with that node as the
13847 * context node, with the number of nodes in the
13848 * node-set as the context size, and with the proximity
13849 * position of the node in the node-set with respect to
13850 * the axis as the context position;"
13851 * @oldset is the node-set" to be filtered.
13852 *
13853 * SPEC XPath 1.0:
13854 * "only predicates change the context position and
13855 * context size (see [2.4 Predicates])."
13856 * Example:
13857 * node-set context pos
13858 * nA 1
13859 * nB 2
13860 * nC 3
13861 * After applying predicate [position() > 1] :
13862 * node-set context pos
13863 * nB 1
13864 * nC 2
13865 *
13866 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013867 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013868 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013869 for (i = 0; i < oldset->nodeNr; i++) {
13870 /*
13871 * Run the evaluation with a node list made of
13872 * a single item in the nodeset.
13873 */
13874 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013875 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13876 (oldset->nodeTab[i]->doc != NULL))
13877 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013878 if (tmp == NULL) {
13879 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13880 ctxt->context->node);
13881 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013882 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13883 ctxt->context->node) < 0) {
13884 ctxt->error = XPATH_MEMORY_ERROR;
13885 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013886 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013887 valuePush(ctxt, tmp);
13888 ctxt->context->contextSize = oldset->nodeNr;
13889 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013890 /*
13891 * Evaluate the predicate against the context node.
13892 * Can/should we optimize position() predicates
13893 * here (e.g. "[1]")?
13894 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013895 if (op->ch2 != -1)
13896 total +=
13897 xmlXPathCompOpEval(ctxt,
13898 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013899 if (ctxt->error != XPATH_EXPRESSION_OK) {
13900 xmlXPathFreeNodeSet(newset);
13901 xmlXPathFreeObject(obj);
13902 return(0);
13903 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013904
Daniel Veillardf06307e2001-07-03 10:35:50 +000013905 /*
William M. Brack08171912003-12-29 02:52:11 +000013906 * The result of the evaluation needs to be tested to
13907 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013908 */
13909 /*
13910 * OPTIMIZE TODO: Can we use
13911 * xmlXPathNodeSetAdd*Unique()* instead?
13912 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013913 res = valuePop(ctxt);
13914 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013915 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13916 < 0)
13917 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013918 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013919
Daniel Veillardf06307e2001-07-03 10:35:50 +000013920 /*
13921 * Cleanup
13922 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013923 if (res != NULL) {
13924 xmlXPathReleaseObject(ctxt->context, res);
13925 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013926 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013927 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013928 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013929 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013930 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013931 * in order to avoid massive recreation inside this
13932 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013933 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013934 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013935 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013936 ctxt->context->node = NULL;
13937 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013938 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013939 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013940 /*
13941 * The result is used as the new evaluation set.
13942 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013943 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013944 ctxt->context->node = NULL;
13945 ctxt->context->contextSize = -1;
13946 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013947 /* may want to move this past the '}' later */
13948 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013949 valuePush(ctxt,
13950 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013951 }
13952 ctxt->context->node = oldnode;
13953 return (total);
13954 }
13955 case XPATH_OP_SORT:
13956 if (op->ch1 != -1)
13957 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013958 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013959 if ((ctxt->value != NULL) &&
13960 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013961 (ctxt->value->nodesetval != NULL) &&
13962 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013963 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013964 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013965 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013966 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013967#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013968 case XPATH_OP_RANGETO:{
13969 xmlXPathObjectPtr range;
13970 xmlXPathObjectPtr res, obj;
13971 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013972 xmlLocationSetPtr newlocset = NULL;
13973 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013974 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013975 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013976
Daniel Veillardf06307e2001-07-03 10:35:50 +000013977 if (op->ch1 != -1)
13978 total +=
13979 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13980 if (op->ch2 == -1)
13981 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013982
William M. Brack08171912003-12-29 02:52:11 +000013983 if (ctxt->value->type == XPATH_LOCATIONSET) {
13984 /*
13985 * Extract the old locset, and then evaluate the result of the
13986 * expression for all the element in the locset. use it to grow
13987 * up a new locset.
13988 */
13989 CHECK_TYPE0(XPATH_LOCATIONSET);
13990 obj = valuePop(ctxt);
13991 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013992
William M. Brack08171912003-12-29 02:52:11 +000013993 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013994 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013995 ctxt->context->contextSize = 0;
13996 ctxt->context->proximityPosition = 0;
13997 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13998 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013999 if (res != NULL) {
14000 xmlXPathReleaseObject(ctxt->context, res);
14001 }
William M. Brack08171912003-12-29 02:52:11 +000014002 valuePush(ctxt, obj);
14003 CHECK_ERROR0;
14004 return (total);
14005 }
14006 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014007
William M. Brack08171912003-12-29 02:52:11 +000014008 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014009 /*
William M. Brack08171912003-12-29 02:52:11 +000014010 * Run the evaluation with a node list made of a
14011 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000014012 */
William M. Brackf7eb7942003-12-31 07:59:17 +000014013 ctxt->context->node = oldlocset->locTab[i]->user;
14014 ctxt->context->contextSize = oldlocset->locNr;
14015 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014016 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14017 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014018 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014019
Daniel Veillardf06307e2001-07-03 10:35:50 +000014020 if (op->ch2 != -1)
14021 total +=
14022 xmlXPathCompOpEval(ctxt,
14023 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014024 if (ctxt->error != XPATH_EXPRESSION_OK) {
14025 xmlXPathFreeObject(obj);
14026 return(0);
14027 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014028
Daniel Veillardf06307e2001-07-03 10:35:50 +000014029 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000014030 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014031 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000014032 (xmlLocationSetPtr)res->user;
14033 for (j=0; j<rloc->locNr; j++) {
14034 range = xmlXPtrNewRange(
14035 oldlocset->locTab[i]->user,
14036 oldlocset->locTab[i]->index,
14037 rloc->locTab[j]->user2,
14038 rloc->locTab[j]->index2);
14039 if (range != NULL) {
14040 xmlXPtrLocationSetAdd(newlocset, range);
14041 }
14042 }
14043 } else {
14044 range = xmlXPtrNewRangeNodeObject(
14045 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14046 if (range != NULL) {
14047 xmlXPtrLocationSetAdd(newlocset,range);
14048 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014049 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014050
Daniel Veillardf06307e2001-07-03 10:35:50 +000014051 /*
14052 * Cleanup
14053 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014054 if (res != NULL) {
14055 xmlXPathReleaseObject(ctxt->context, res);
14056 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014057 if (ctxt->value == tmp) {
14058 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014059 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014060 }
14061
14062 ctxt->context->node = NULL;
14063 }
William M. Brack72ee48d2003-12-30 08:30:19 +000014064 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000014065 CHECK_TYPE0(XPATH_NODESET);
14066 obj = valuePop(ctxt);
14067 oldset = obj->nodesetval;
14068 ctxt->context->node = NULL;
14069
14070 newlocset = xmlXPtrLocationSetCreate(NULL);
14071
14072 if (oldset != NULL) {
14073 for (i = 0; i < oldset->nodeNr; i++) {
14074 /*
14075 * Run the evaluation with a node list made of a single item
14076 * in the nodeset.
14077 */
14078 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014079 /*
14080 * OPTIMIZE TODO: Avoid recreation for every iteration.
14081 */
14082 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14083 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000014084 valuePush(ctxt, tmp);
14085
14086 if (op->ch2 != -1)
14087 total +=
14088 xmlXPathCompOpEval(ctxt,
14089 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014090 if (ctxt->error != XPATH_EXPRESSION_OK) {
14091 xmlXPathFreeObject(obj);
14092 return(0);
14093 }
William M. Brack08171912003-12-29 02:52:11 +000014094
William M. Brack08171912003-12-29 02:52:11 +000014095 res = valuePop(ctxt);
14096 range =
14097 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14098 res);
14099 if (range != NULL) {
14100 xmlXPtrLocationSetAdd(newlocset, range);
14101 }
14102
14103 /*
14104 * Cleanup
14105 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014106 if (res != NULL) {
14107 xmlXPathReleaseObject(ctxt->context, res);
14108 }
William M. Brack08171912003-12-29 02:52:11 +000014109 if (ctxt->value == tmp) {
14110 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014111 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000014112 }
14113
14114 ctxt->context->node = NULL;
14115 }
14116 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014117 }
14118
14119 /*
14120 * The result is used as the new evaluation set.
14121 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014122 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014123 ctxt->context->node = NULL;
14124 ctxt->context->contextSize = -1;
14125 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000014126 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014127 return (total);
14128 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014129#endif /* LIBXML_XPTR_ENABLED */
14130 }
14131 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000014132 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080014133 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014134 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014135}
14136
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014137/**
14138 * xmlXPathCompOpEvalToBoolean:
14139 * @ctxt: the XPath parser context
14140 *
14141 * Evaluates if the expression evaluates to true.
14142 *
14143 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14144 */
14145static int
14146xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014147 xmlXPathStepOpPtr op,
14148 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014149{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014150 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014151
14152start:
14153 /* comp = ctxt->comp; */
14154 switch (op->op) {
14155 case XPATH_OP_END:
14156 return (0);
14157 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014158 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014159 if (isPredicate)
14160 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14161 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014162 case XPATH_OP_SORT:
14163 /*
14164 * We don't need sorting for boolean results. Skip this one.
14165 */
14166 if (op->ch1 != -1) {
14167 op = &ctxt->comp->steps[op->ch1];
14168 goto start;
14169 }
14170 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014171 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014172 if (op->ch1 == -1)
14173 return(0);
14174
14175 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14176 if (ctxt->error != XPATH_EXPRESSION_OK)
14177 return(-1);
14178
14179 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14180 if (ctxt->error != XPATH_EXPRESSION_OK)
14181 return(-1);
14182
14183 resObj = valuePop(ctxt);
14184 if (resObj == NULL)
14185 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014186 break;
14187 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014188 /*
14189 * Fallback to call xmlXPathCompOpEval().
14190 */
14191 xmlXPathCompOpEval(ctxt, op);
14192 if (ctxt->error != XPATH_EXPRESSION_OK)
14193 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014194
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014195 resObj = valuePop(ctxt);
14196 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014197 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014198 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014199 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014200
14201 if (resObj) {
14202 int res;
14203
14204 if (resObj->type == XPATH_BOOLEAN) {
14205 res = resObj->boolval;
14206 } else if (isPredicate) {
14207 /*
14208 * For predicates a result of type "number" is handled
14209 * differently:
14210 * SPEC XPath 1.0:
14211 * "If the result is a number, the result will be converted
14212 * to true if the number is equal to the context position
14213 * and will be converted to false otherwise;"
14214 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014215 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014216 } else {
14217 res = xmlXPathCastToBoolean(resObj);
14218 }
14219 xmlXPathReleaseObject(ctxt->context, resObj);
14220 return(res);
14221 }
14222
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014223 return(0);
14224}
14225
Daniel Veillard56de87e2005-02-16 00:22:29 +000014226#ifdef XPATH_STREAMING
14227/**
14228 * xmlXPathRunStreamEval:
14229 * @ctxt: the XPath parser context with the compiled expression
14230 *
14231 * Evaluate the Precompiled Streamable XPath expression in the given context.
14232 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014233static int
14234xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14235 xmlXPathObjectPtr *resultSeq, int toBool)
14236{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014237 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014238 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014239 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014240 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014241 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014242 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014243
14244 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014245
14246 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014247 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014248 max_depth = xmlPatternMaxDepth(comp);
14249 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014250 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014251 if (max_depth == -2)
14252 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014253 min_depth = xmlPatternMinDepth(comp);
14254 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014255 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014256 from_root = xmlPatternFromRoot(comp);
14257 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014258 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014259#if 0
14260 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14261#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014262
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014263 if (! toBool) {
14264 if (resultSeq == NULL)
14265 return(-1);
14266 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14267 if (*resultSeq == NULL)
14268 return(-1);
14269 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014270
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014271 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014272 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014273 */
14274 if (min_depth == 0) {
14275 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014276 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014277 if (toBool)
14278 return(1);
14279 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014280 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014281 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014282 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014283 if (toBool)
14284 return(1);
14285 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014286 }
14287 }
14288 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014289 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014290 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014291
Daniel Veillard56de87e2005-02-16 00:22:29 +000014292 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014293 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014294 } else if (ctxt->node != NULL) {
14295 switch (ctxt->node->type) {
14296 case XML_ELEMENT_NODE:
14297 case XML_DOCUMENT_NODE:
14298 case XML_DOCUMENT_FRAG_NODE:
14299 case XML_HTML_DOCUMENT_NODE:
14300#ifdef LIBXML_DOCB_ENABLED
14301 case XML_DOCB_DOCUMENT_NODE:
14302#endif
14303 cur = ctxt->node;
14304 break;
14305 case XML_ATTRIBUTE_NODE:
14306 case XML_TEXT_NODE:
14307 case XML_CDATA_SECTION_NODE:
14308 case XML_ENTITY_REF_NODE:
14309 case XML_ENTITY_NODE:
14310 case XML_PI_NODE:
14311 case XML_COMMENT_NODE:
14312 case XML_NOTATION_NODE:
14313 case XML_DTD_NODE:
14314 case XML_DOCUMENT_TYPE_NODE:
14315 case XML_ELEMENT_DECL:
14316 case XML_ATTRIBUTE_DECL:
14317 case XML_ENTITY_DECL:
14318 case XML_NAMESPACE_DECL:
14319 case XML_XINCLUDE_START:
14320 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014321 break;
14322 }
14323 limit = cur;
14324 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014325 if (cur == NULL) {
14326 return(0);
14327 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014328
14329 patstream = xmlPatternGetStreamCtxt(comp);
14330 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014331 /*
14332 * QUESTION TODO: Is this an error?
14333 */
14334 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014335 }
14336
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014337 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014338
Daniel Veillard56de87e2005-02-16 00:22:29 +000014339 if (from_root) {
14340 ret = xmlStreamPush(patstream, NULL, NULL);
14341 if (ret < 0) {
14342 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014343 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014344 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014345 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014346 }
14347 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014348 depth = 0;
14349 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014350next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014351 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014352 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014353
14354 switch (cur->type) {
14355 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014356 case XML_TEXT_NODE:
14357 case XML_CDATA_SECTION_NODE:
14358 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014359 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014360 if (cur->type == XML_ELEMENT_NODE) {
14361 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014362 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014363 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014364 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14365 else
14366 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014367
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014368 if (ret < 0) {
14369 /* NOP. */
14370 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014371 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014372 goto return_1;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014373 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14374 < 0) {
14375 ctxt->lastError.domain = XML_FROM_XPATH;
14376 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14377 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014378 }
14379 if ((cur->children == NULL) || (depth >= max_depth)) {
14380 ret = xmlStreamPop(patstream);
14381 while (cur->next != NULL) {
14382 cur = cur->next;
14383 if ((cur->type != XML_ENTITY_DECL) &&
14384 (cur->type != XML_DTD_NODE))
14385 goto next_node;
14386 }
14387 }
14388 default:
14389 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014390 }
14391
Daniel Veillard56de87e2005-02-16 00:22:29 +000014392scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080014393 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014394 if ((cur->children != NULL) && (depth < max_depth)) {
14395 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014396 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014397 */
14398 if (cur->children->type != XML_ENTITY_DECL) {
14399 cur = cur->children;
14400 depth++;
14401 /*
14402 * Skip DTDs
14403 */
14404 if (cur->type != XML_DTD_NODE)
14405 continue;
14406 }
14407 }
14408
14409 if (cur == limit)
14410 break;
14411
14412 while (cur->next != NULL) {
14413 cur = cur->next;
14414 if ((cur->type != XML_ENTITY_DECL) &&
14415 (cur->type != XML_DTD_NODE))
14416 goto next_node;
14417 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014418
Daniel Veillard56de87e2005-02-16 00:22:29 +000014419 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014420 cur = cur->parent;
14421 depth--;
14422 if ((cur == NULL) || (cur == limit))
14423 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014424 if (cur->type == XML_ELEMENT_NODE) {
14425 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014426 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014427 ((cur->type == XML_TEXT_NODE) ||
14428 (cur->type == XML_CDATA_SECTION_NODE) ||
14429 (cur->type == XML_COMMENT_NODE) ||
14430 (cur->type == XML_PI_NODE)))
14431 {
14432 ret = xmlStreamPop(patstream);
14433 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014434 if (cur->next != NULL) {
14435 cur = cur->next;
14436 break;
14437 }
14438 } while (cur != NULL);
14439
14440 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014441
Daniel Veillard56de87e2005-02-16 00:22:29 +000014442done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014443
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014444#if 0
14445 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014446 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014447#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014448
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014449 if (patstream)
14450 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014451 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014452
14453return_1:
14454 if (patstream)
14455 xmlFreeStreamCtxt(patstream);
14456 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014457}
14458#endif /* XPATH_STREAMING */
14459
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014460/**
14461 * xmlXPathRunEval:
14462 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014463 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014464 *
14465 * Evaluate the Precompiled XPath expression in the given context.
14466 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014467static int
14468xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14469{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014470 xmlXPathCompExprPtr comp;
14471
14472 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014473 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014474
14475 if (ctxt->valueTab == NULL) {
14476 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014477 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014478 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14479 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014480 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014481 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014482 }
14483 ctxt->valueNr = 0;
14484 ctxt->valueMax = 10;
14485 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014486 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014487 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014488#ifdef XPATH_STREAMING
14489 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014490 int res;
14491
14492 if (toBool) {
14493 /*
14494 * Evaluation to boolean result.
14495 */
14496 res = xmlXPathRunStreamEval(ctxt->context,
14497 ctxt->comp->stream, NULL, 1);
14498 if (res != -1)
14499 return(res);
14500 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014501 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014502
14503 /*
14504 * Evaluation to a sequence.
14505 */
14506 res = xmlXPathRunStreamEval(ctxt->context,
14507 ctxt->comp->stream, &resObj, 0);
14508
14509 if ((res != -1) && (resObj != NULL)) {
14510 valuePush(ctxt, resObj);
14511 return(0);
14512 }
14513 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014514 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014515 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014516 /*
14517 * QUESTION TODO: This falls back to normal XPath evaluation
14518 * if res == -1. Is this intended?
14519 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014520 }
14521#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014522 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014523 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014524 xmlGenericError(xmlGenericErrorContext,
14525 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014526 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014527 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014528 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014529 return(xmlXPathCompOpEvalToBoolean(ctxt,
14530 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014531 else
14532 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14533
14534 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014535}
14536
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014537/************************************************************************
14538 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014539 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014540 * *
14541 ************************************************************************/
14542
14543/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014544 * xmlXPathEvalPredicate:
14545 * @ctxt: the XPath context
14546 * @res: the Predicate Expression evaluation result
14547 *
14548 * Evaluate a predicate result for the current node.
14549 * A PredicateExpr is evaluated by evaluating the Expr and converting
14550 * the result to a boolean. If the result is a number, the result will
14551 * be converted to true if the number is equal to the position of the
14552 * context node in the context node list (as returned by the position
14553 * function) and will be converted to false otherwise; if the result
14554 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014555 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014556 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014557 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014558 */
14559int
14560xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014561 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014562 switch (res->type) {
14563 case XPATH_BOOLEAN:
14564 return(res->boolval);
14565 case XPATH_NUMBER:
14566 return(res->floatval == ctxt->proximityPosition);
14567 case XPATH_NODESET:
14568 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014569 if (res->nodesetval == NULL)
14570 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014571 return(res->nodesetval->nodeNr != 0);
14572 case XPATH_STRING:
14573 return((res->stringval != NULL) &&
14574 (xmlStrlen(res->stringval) != 0));
14575 default:
14576 STRANGE
14577 }
14578 return(0);
14579}
14580
14581/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014582 * xmlXPathEvaluatePredicateResult:
14583 * @ctxt: the XPath Parser context
14584 * @res: the Predicate Expression evaluation result
14585 *
14586 * Evaluate a predicate result for the current node.
14587 * A PredicateExpr is evaluated by evaluating the Expr and converting
14588 * the result to a boolean. If the result is a number, the result will
14589 * be converted to true if the number is equal to the position of the
14590 * context node in the context node list (as returned by the position
14591 * function) and will be converted to false otherwise; if the result
14592 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014593 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014594 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014595 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014596 */
14597int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014598xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014599 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014600 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014601 switch (res->type) {
14602 case XPATH_BOOLEAN:
14603 return(res->boolval);
14604 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014605#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014606 return((res->floatval == ctxt->context->proximityPosition) &&
14607 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014608#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014609 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014610#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014611 case XPATH_NODESET:
14612 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014613 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014614 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014615 return(res->nodesetval->nodeNr != 0);
14616 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014617 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014618#ifdef LIBXML_XPTR_ENABLED
14619 case XPATH_LOCATIONSET:{
14620 xmlLocationSetPtr ptr = res->user;
14621 if (ptr == NULL)
14622 return(0);
14623 return (ptr->locNr != 0);
14624 }
14625#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014626 default:
14627 STRANGE
14628 }
14629 return(0);
14630}
14631
Daniel Veillard56de87e2005-02-16 00:22:29 +000014632#ifdef XPATH_STREAMING
14633/**
14634 * xmlXPathTryStreamCompile:
14635 * @ctxt: an XPath context
14636 * @str: the XPath expression
14637 *
14638 * Try to compile the XPath expression as a streamable subset.
14639 *
14640 * Returns the compiled expression or NULL if failed to compile.
14641 */
14642static xmlXPathCompExprPtr
14643xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14644 /*
14645 * Optimization: use streaming patterns when the XPath expression can
14646 * be compiled to a stream lookup
14647 */
14648 xmlPatternPtr stream;
14649 xmlXPathCompExprPtr comp;
14650 xmlDictPtr dict = NULL;
14651 const xmlChar **namespaces = NULL;
14652 xmlNsPtr ns;
14653 int i, j;
14654
14655 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14656 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014657 const xmlChar *tmp;
14658
14659 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014660 * We don't try to handle expressions using the verbose axis
14661 * specifiers ("::"), just the simplied form at this point.
14662 * Additionally, if there is no list of namespaces available and
14663 * there's a ":" in the expression, indicating a prefixed QName,
14664 * then we won't try to compile either. xmlPatterncompile() needs
14665 * to have a list of namespaces at compilation time in order to
14666 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014667 */
14668 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014669 if ((tmp != NULL) &&
14670 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014671 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014672
Daniel Veillard56de87e2005-02-16 00:22:29 +000014673 if (ctxt != NULL) {
14674 dict = ctxt->dict;
14675 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014676 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014677 if (namespaces == NULL) {
14678 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14679 return(NULL);
14680 }
14681 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14682 ns = ctxt->namespaces[j];
14683 namespaces[i++] = ns->href;
14684 namespaces[i++] = ns->prefix;
14685 }
14686 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014687 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014688 }
14689 }
14690
William M. Brackea152c02005-06-09 18:12:28 +000014691 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14692 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014693 if (namespaces != NULL) {
14694 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014695 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014696 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14697 comp = xmlXPathNewCompExpr();
14698 if (comp == NULL) {
14699 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14700 return(NULL);
14701 }
14702 comp->stream = stream;
14703 comp->dict = dict;
14704 if (comp->dict)
14705 xmlDictReference(comp->dict);
14706 return(comp);
14707 }
14708 xmlFreePattern(stream);
14709 }
14710 return(NULL);
14711}
14712#endif /* XPATH_STREAMING */
14713
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014714static void
Nick Wellnhofer62270532012-08-19 19:42:38 +020014715xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014716{
14717 /*
14718 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14719 * internal representation.
14720 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014721
Nick Wellnhofer62270532012-08-19 19:42:38 +020014722 if ((op->ch1 != -1) &&
14723 (op->op == XPATH_OP_COLLECT /* 11 */))
14724 {
14725 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14726
14727 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14728 ((xmlXPathAxisVal) prevop->value ==
14729 AXIS_DESCENDANT_OR_SELF) &&
14730 (prevop->ch2 == -1) &&
14731 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14732 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14733 {
14734 /*
14735 * This is a "descendant-or-self::node()" without predicates.
14736 * Try to eliminate it.
14737 */
14738
14739 switch ((xmlXPathAxisVal) op->value) {
14740 case AXIS_CHILD:
14741 case AXIS_DESCENDANT:
14742 /*
14743 * Convert "descendant-or-self::node()/child::" or
14744 * "descendant-or-self::node()/descendant::" to
14745 * "descendant::"
14746 */
14747 op->ch1 = prevop->ch1;
14748 op->value = AXIS_DESCENDANT;
14749 break;
14750 case AXIS_SELF:
14751 case AXIS_DESCENDANT_OR_SELF:
14752 /*
14753 * Convert "descendant-or-self::node()/self::" or
14754 * "descendant-or-self::node()/descendant-or-self::" to
14755 * to "descendant-or-self::"
14756 */
14757 op->ch1 = prevop->ch1;
14758 op->value = AXIS_DESCENDANT_OR_SELF;
14759 break;
14760 default:
14761 break;
14762 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014763 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014764 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014765
14766 /* Recurse */
14767 if (op->ch1 != -1)
14768 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014769 if (op->ch2 != -1)
Nick Wellnhofer62270532012-08-19 19:42:38 +020014770 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014771}
14772
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014773/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014774 * xmlXPathCtxtCompile:
14775 * @ctxt: an XPath context
14776 * @str: the XPath expression
14777 *
14778 * Compile an XPath expression
14779 *
14780 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14781 * the caller has to free the object.
14782 */
14783xmlXPathCompExprPtr
14784xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14785 xmlXPathParserContextPtr pctxt;
14786 xmlXPathCompExprPtr comp;
14787
Daniel Veillard56de87e2005-02-16 00:22:29 +000014788#ifdef XPATH_STREAMING
14789 comp = xmlXPathTryStreamCompile(ctxt, str);
14790 if (comp != NULL)
14791 return(comp);
14792#endif
14793
Daniel Veillard4773df22004-01-23 13:15:13 +000014794 xmlXPathInit();
14795
14796 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014797 if (pctxt == NULL)
14798 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014799 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014800
14801 if( pctxt->error != XPATH_EXPRESSION_OK )
14802 {
14803 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014804 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014805 }
14806
14807 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014808 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014809 * aleksey: in some cases this line prints *second* error message
14810 * (see bug #78858) and probably this should be fixed.
14811 * However, we are not sure that all error messages are printed
14812 * out in other places. It's not critical so we leave it as-is for now
14813 */
14814 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14815 comp = NULL;
14816 } else {
14817 comp = pctxt->comp;
14818 pctxt->comp = NULL;
14819 }
14820 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014821
Daniel Veillard4773df22004-01-23 13:15:13 +000014822 if (comp != NULL) {
14823 comp->expr = xmlStrdup(str);
14824#ifdef DEBUG_EVAL_COUNTS
14825 comp->string = xmlStrdup(str);
14826 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014827#endif
Nick Wellnhofer62270532012-08-19 19:42:38 +020014828 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14829 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014830 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014831 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014832 return(comp);
14833}
14834
14835/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014836 * xmlXPathCompile:
14837 * @str: the XPath expression
14838 *
14839 * Compile an XPath expression
14840 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014841 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014842 * the caller has to free the object.
14843 */
14844xmlXPathCompExprPtr
14845xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014846 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014847}
14848
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014849/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014850 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014851 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014852 * @ctxt: the XPath context
14853 * @resObj: the resulting XPath object or NULL
14854 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014855 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014856 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014857 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014858 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014859 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014860 * the caller has to free the object.
14861 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014862static int
14863xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14864 xmlXPathContextPtr ctxt,
14865 xmlXPathObjectPtr *resObj,
14866 int toBool)
14867{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014868 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014869#ifndef LIBXML_THREAD_ENABLED
14870 static int reentance = 0;
14871#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014872 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014873
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014874 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014875
14876 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014877 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014878 xmlXPathInit();
14879
Daniel Veillard81463942001-10-16 12:34:39 +000014880#ifndef LIBXML_THREAD_ENABLED
14881 reentance++;
14882 if (reentance > 1)
14883 xmlXPathDisableOptimizer = 1;
14884#endif
14885
Daniel Veillardf06307e2001-07-03 10:35:50 +000014886#ifdef DEBUG_EVAL_COUNTS
14887 comp->nb++;
14888 if ((comp->string != NULL) && (comp->nb > 100)) {
14889 fprintf(stderr, "100 x %s\n", comp->string);
14890 comp->nb = 0;
14891 }
14892#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014893 pctxt = xmlXPathCompParserContext(comp, ctxt);
14894 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014895
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014896 if (resObj) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014897 if (pctxt->value == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014898 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014899 "xmlXPathCompiledEval: evaluation failed\n");
Daniel Veillard45490ae2008-07-29 09:13:19 +000014900 *resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014901 } else {
14902 *resObj = valuePop(pctxt);
14903 }
Owen Taylor3473f882001-02-23 17:55:21 +000014904 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014905
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014906 /*
14907 * Pop all remaining objects from the stack.
14908 */
14909 if (pctxt->valueNr > 0) {
14910 xmlXPathObjectPtr tmp;
14911 int stack = 0;
14912
14913 do {
14914 tmp = valuePop(pctxt);
14915 if (tmp != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014916 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014917 xmlXPathReleaseObject(ctxt, tmp);
14918 }
14919 } while (tmp != NULL);
14920 if ((stack != 0) &&
14921 ((toBool) || ((resObj) && (*resObj))))
14922 {
14923 xmlGenericError(xmlGenericErrorContext,
14924 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14925 stack);
14926 }
Owen Taylor3473f882001-02-23 17:55:21 +000014927 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014928
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014929 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14930 xmlXPathFreeObject(*resObj);
14931 *resObj = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014932 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014933 pctxt->comp = NULL;
14934 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014935#ifndef LIBXML_THREAD_ENABLED
14936 reentance--;
14937#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014938
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014939 return(res);
14940}
14941
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014942/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014943 * xmlXPathCompiledEval:
14944 * @comp: the compiled XPath expression
14945 * @ctx: the XPath context
14946 *
14947 * Evaluate the Precompiled XPath expression in the given context.
14948 *
14949 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14950 * the caller has to free the object.
14951 */
14952xmlXPathObjectPtr
14953xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14954{
14955 xmlXPathObjectPtr res = NULL;
14956
14957 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14958 return(res);
14959}
14960
14961/**
14962 * xmlXPathCompiledEvalToBoolean:
14963 * @comp: the compiled XPath expression
14964 * @ctxt: the XPath context
14965 *
14966 * Applies the XPath boolean() function on the result of the given
14967 * compiled expression.
14968 *
14969 * Returns 1 if the expression evaluated to true, 0 if to false and
14970 * -1 in API and internal errors.
14971 */
14972int
14973xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14974 xmlXPathContextPtr ctxt)
14975{
14976 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14977}
14978
14979/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014980 * xmlXPathEvalExpr:
14981 * @ctxt: the XPath Parser context
14982 *
14983 * Parse and evaluate an XPath expression in the given context,
14984 * then push the result on the context stack
14985 */
14986void
14987xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014988#ifdef XPATH_STREAMING
14989 xmlXPathCompExprPtr comp;
14990#endif
14991
Daniel Veillarda82b1822004-11-08 16:24:57 +000014992 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014993
Daniel Veillard56de87e2005-02-16 00:22:29 +000014994#ifdef XPATH_STREAMING
14995 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14996 if (comp != NULL) {
14997 if (ctxt->comp != NULL)
14998 xmlXPathFreeCompExpr(ctxt->comp);
14999 ctxt->comp = comp;
15000 if (ctxt->cur != NULL)
15001 while (*ctxt->cur != 0) ctxt->cur++;
15002 } else
15003#endif
15004 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000015005 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000015006 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
15007 (ctxt->comp != NULL) &&
Nick Wellnhofer62270532012-08-19 19:42:38 +020015008 (ctxt->comp->nbStep > 1) &&
15009 (ctxt->comp->last >= 0))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000015010 {
Nick Wellnhofer62270532012-08-19 19:42:38 +020015011 xmlXPathOptimizeExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000015012 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000015013 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000015014 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000015015 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015016 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000015017}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015018
15019/**
15020 * xmlXPathEval:
15021 * @str: the XPath expression
15022 * @ctx: the XPath context
15023 *
15024 * Evaluate the XPath Location Path in the given context.
15025 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000015026 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015027 * the caller has to free the object.
15028 */
15029xmlXPathObjectPtr
15030xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15031 xmlXPathParserContextPtr ctxt;
15032 xmlXPathObjectPtr res, tmp, init = NULL;
15033 int stack = 0;
15034
William M. Brackf13f77f2004-11-12 16:03:48 +000015035 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015036
William M. Brackf13f77f2004-11-12 16:03:48 +000015037 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015038
15039 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000015040 if (ctxt == NULL)
15041 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015042 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015043
15044 if (ctxt->value == NULL) {
15045 xmlGenericError(xmlGenericErrorContext,
15046 "xmlXPathEval: evaluation failed\n");
15047 res = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015048 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
Daniel Veillard56de87e2005-02-16 00:22:29 +000015049#ifdef XPATH_STREAMING
15050 && (ctxt->comp->stream == NULL)
15051#endif
15052 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015053 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15054 res = NULL;
15055 } else {
15056 res = valuePop(ctxt);
15057 }
15058
15059 do {
15060 tmp = valuePop(ctxt);
15061 if (tmp != NULL) {
15062 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015063 stack++;
15064 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015065 }
15066 } while (tmp != NULL);
15067 if ((stack != 0) && (res != NULL)) {
15068 xmlGenericError(xmlGenericErrorContext,
15069 "xmlXPathEval: %d object left on the stack\n",
15070 stack);
15071 }
15072 if (ctxt->error != XPATH_EXPRESSION_OK) {
15073 xmlXPathFreeObject(res);
15074 res = NULL;
15075 }
15076
Owen Taylor3473f882001-02-23 17:55:21 +000015077 xmlXPathFreeParserContext(ctxt);
15078 return(res);
15079}
15080
15081/**
15082 * xmlXPathEvalExpression:
15083 * @str: the XPath expression
15084 * @ctxt: the XPath context
15085 *
15086 * Evaluate the XPath expression in the given context.
15087 *
15088 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15089 * the caller has to free the object.
15090 */
15091xmlXPathObjectPtr
15092xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15093 xmlXPathParserContextPtr pctxt;
15094 xmlXPathObjectPtr res, tmp;
15095 int stack = 0;
15096
William M. Brackf13f77f2004-11-12 16:03:48 +000015097 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000015098
William M. Brackf13f77f2004-11-12 16:03:48 +000015099 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000015100
15101 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000015102 if (pctxt == NULL)
15103 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000015104 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000015105
Daniel Veillardc465ffc2006-10-17 19:39:33 +000015106 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000015107 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15108 res = NULL;
15109 } else {
15110 res = valuePop(pctxt);
15111 }
15112 do {
15113 tmp = valuePop(pctxt);
15114 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015115 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000015116 stack++;
15117 }
15118 } while (tmp != NULL);
15119 if ((stack != 0) && (res != NULL)) {
15120 xmlGenericError(xmlGenericErrorContext,
15121 "xmlXPathEvalExpression: %d object left on the stack\n",
15122 stack);
15123 }
15124 xmlXPathFreeParserContext(pctxt);
15125 return(res);
15126}
15127
Daniel Veillard42766c02002-08-22 20:52:17 +000015128/************************************************************************
15129 * *
15130 * Extra functions not pertaining to the XPath spec *
15131 * *
15132 ************************************************************************/
15133/**
15134 * xmlXPathEscapeUriFunction:
15135 * @ctxt: the XPath Parser context
15136 * @nargs: the number of arguments
15137 *
15138 * Implement the escape-uri() XPath function
15139 * string escape-uri(string $str, bool $escape-reserved)
15140 *
15141 * This function applies the URI escaping rules defined in section 2 of [RFC
15142 * 2396] to the string supplied as $uri-part, which typically represents all
15143 * or part of a URI. The effect of the function is to replace any special
15144 * character in the string by an escape sequence of the form %xx%yy...,
15145 * where xxyy... is the hexadecimal representation of the octets used to
15146 * represent the character in UTF-8.
15147 *
15148 * The set of characters that are escaped depends on the setting of the
15149 * boolean argument $escape-reserved.
15150 *
15151 * If $escape-reserved is true, all characters are escaped other than lower
15152 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15153 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15154 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15155 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15156 * A-F).
15157 *
15158 * If $escape-reserved is false, the behavior differs in that characters
15159 * referred to in [RFC 2396] as reserved characters are not escaped. These
15160 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015161 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015162 * [RFC 2396] does not define whether escaped URIs should use lower case or
15163 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15164 * compared using string comparison functions, this function must always use
15165 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015166 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015167 * Generally, $escape-reserved should be set to true when escaping a string
15168 * that is to form a single part of a URI, and to false when escaping an
15169 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015170 *
15171 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015172 * utf-8 and then converted according to RFC 2396.
15173 *
15174 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015175 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015176 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15177 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15178 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15179 *
15180 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015181static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015182xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15183 xmlXPathObjectPtr str;
15184 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080015185 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000015186 xmlChar *cptr;
15187 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015188
Daniel Veillard42766c02002-08-22 20:52:17 +000015189 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015190
Daniel Veillard42766c02002-08-22 20:52:17 +000015191 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015192
Daniel Veillard42766c02002-08-22 20:52:17 +000015193 CAST_TO_STRING;
15194 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015195
Daniel Veillardade10f22012-07-12 09:43:27 +080015196 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015197
Daniel Veillard42766c02002-08-22 20:52:17 +000015198 escape[0] = '%';
15199 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015200
Daniel Veillard42766c02002-08-22 20:52:17 +000015201 if (target) {
15202 for (cptr = str->stringval; *cptr; cptr++) {
15203 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15204 (*cptr >= 'a' && *cptr <= 'z') ||
15205 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015206 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015207 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15208 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015209 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015210 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15211 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15212 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15213 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15214 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15215 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15216 (!escape_reserved &&
15217 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15218 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15219 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15220 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080015221 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000015222 } else {
15223 if ((*cptr >> 4) < 10)
15224 escape[1] = '0' + (*cptr >> 4);
15225 else
15226 escape[1] = 'A' - 10 + (*cptr >> 4);
15227 if ((*cptr & 0xF) < 10)
15228 escape[2] = '0' + (*cptr & 0xF);
15229 else
15230 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015231
Daniel Veillardade10f22012-07-12 09:43:27 +080015232 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000015233 }
15234 }
15235 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015236 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080015237 xmlBufContent(target)));
15238 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015239 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015240}
15241
Owen Taylor3473f882001-02-23 17:55:21 +000015242/**
15243 * xmlXPathRegisterAllFunctions:
15244 * @ctxt: the XPath context
15245 *
15246 * Registers all default XPath functions in this context
15247 */
15248void
15249xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15250{
15251 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15252 xmlXPathBooleanFunction);
15253 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15254 xmlXPathCeilingFunction);
15255 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15256 xmlXPathCountFunction);
15257 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15258 xmlXPathConcatFunction);
15259 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15260 xmlXPathContainsFunction);
15261 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15262 xmlXPathIdFunction);
15263 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15264 xmlXPathFalseFunction);
15265 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15266 xmlXPathFloorFunction);
15267 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15268 xmlXPathLastFunction);
15269 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15270 xmlXPathLangFunction);
15271 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15272 xmlXPathLocalNameFunction);
15273 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15274 xmlXPathNotFunction);
15275 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15276 xmlXPathNameFunction);
15277 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15278 xmlXPathNamespaceURIFunction);
15279 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15280 xmlXPathNormalizeFunction);
15281 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15282 xmlXPathNumberFunction);
15283 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15284 xmlXPathPositionFunction);
15285 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15286 xmlXPathRoundFunction);
15287 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15288 xmlXPathStringFunction);
15289 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15290 xmlXPathStringLengthFunction);
15291 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15292 xmlXPathStartsWithFunction);
15293 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15294 xmlXPathSubstringFunction);
15295 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15296 xmlXPathSubstringBeforeFunction);
15297 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15298 xmlXPathSubstringAfterFunction);
15299 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15300 xmlXPathSumFunction);
15301 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15302 xmlXPathTrueFunction);
15303 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15304 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015305
15306 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15307 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15308 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015309}
15310
15311#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015312#define bottom_xpath
15313#include "elfgcchack.h"