blob: 701696ef87b1f68908dc23a8325f6931accad590 [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);
2134#ifdef XP_DEBUG_OBJ_USAGE
2135 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2136#endif
2137 return(ret);
2138 }
2139 }
2140 return(xmlXPathNewNodeSet(val));
2141}
2142
2143/**
2144 * xmlXPathCacheNewCString:
2145 * @ctxt: the XPath context
2146 * @val: the char * value
2147 *
2148 * This is the cached version of xmlXPathNewCString().
2149 * Acquire an xmlXPathObjectPtr of type string and of value @val
2150 *
2151 * Returns the created or reused object.
2152 */
2153static xmlXPathObjectPtr
2154xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002155{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002156 if ((ctxt != NULL) && (ctxt->cache)) {
2157 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002158
2159 if ((cache->stringObjs != NULL) &&
2160 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002161 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002162 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002163
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002164 ret = (xmlXPathObjectPtr)
2165 cache->stringObjs->items[--cache->stringObjs->number];
2166
2167 ret->type = XPATH_STRING;
2168 ret->stringval = xmlStrdup(BAD_CAST val);
2169#ifdef XP_DEBUG_OBJ_USAGE
2170 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2171#endif
2172 return(ret);
2173 } else if ((cache->miscObjs != NULL) &&
2174 (cache->miscObjs->number != 0))
2175 {
2176 xmlXPathObjectPtr ret;
2177
2178 ret = (xmlXPathObjectPtr)
2179 cache->miscObjs->items[--cache->miscObjs->number];
2180
2181 ret->type = XPATH_STRING;
2182 ret->stringval = xmlStrdup(BAD_CAST val);
2183#ifdef XP_DEBUG_OBJ_USAGE
2184 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2185#endif
2186 return(ret);
2187 }
2188 }
2189 return(xmlXPathNewCString(val));
2190}
2191
2192/**
2193 * xmlXPathCacheNewString:
2194 * @ctxt: the XPath context
2195 * @val: the xmlChar * value
2196 *
2197 * This is the cached version of xmlXPathNewString().
2198 * Acquire an xmlXPathObjectPtr of type string and of value @val
2199 *
2200 * Returns the created or reused object.
2201 */
2202static xmlXPathObjectPtr
2203xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002204{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002205 if ((ctxt != NULL) && (ctxt->cache)) {
2206 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002207
2208 if ((cache->stringObjs != NULL) &&
2209 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002210 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002211 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002212
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002213 ret = (xmlXPathObjectPtr)
2214 cache->stringObjs->items[--cache->stringObjs->number];
2215 ret->type = XPATH_STRING;
2216 if (val != NULL)
2217 ret->stringval = xmlStrdup(val);
2218 else
2219 ret->stringval = xmlStrdup((const xmlChar *)"");
2220#ifdef XP_DEBUG_OBJ_USAGE
2221 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2222#endif
2223 return(ret);
2224 } else if ((cache->miscObjs != NULL) &&
2225 (cache->miscObjs->number != 0))
2226 {
2227 xmlXPathObjectPtr ret;
2228
2229 ret = (xmlXPathObjectPtr)
2230 cache->miscObjs->items[--cache->miscObjs->number];
2231
2232 ret->type = XPATH_STRING;
2233 if (val != NULL)
2234 ret->stringval = xmlStrdup(val);
2235 else
2236 ret->stringval = xmlStrdup((const xmlChar *)"");
2237#ifdef XP_DEBUG_OBJ_USAGE
2238 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2239#endif
2240 return(ret);
2241 }
2242 }
2243 return(xmlXPathNewString(val));
2244}
2245
2246/**
2247 * xmlXPathCacheNewBoolean:
2248 * @ctxt: the XPath context
2249 * @val: the boolean value
2250 *
2251 * This is the cached version of xmlXPathNewBoolean().
2252 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2253 *
2254 * Returns the created or reused object.
2255 */
2256static xmlXPathObjectPtr
2257xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002258{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002259 if ((ctxt != NULL) && (ctxt->cache)) {
2260 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002261
2262 if ((cache->booleanObjs != NULL) &&
2263 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002264 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002265 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002266
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002267 ret = (xmlXPathObjectPtr)
2268 cache->booleanObjs->items[--cache->booleanObjs->number];
2269 ret->type = XPATH_BOOLEAN;
2270 ret->boolval = (val != 0);
2271#ifdef XP_DEBUG_OBJ_USAGE
2272 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2273#endif
2274 return(ret);
2275 } else if ((cache->miscObjs != NULL) &&
2276 (cache->miscObjs->number != 0))
2277 {
2278 xmlXPathObjectPtr ret;
2279
2280 ret = (xmlXPathObjectPtr)
2281 cache->miscObjs->items[--cache->miscObjs->number];
2282
2283 ret->type = XPATH_BOOLEAN;
2284 ret->boolval = (val != 0);
2285#ifdef XP_DEBUG_OBJ_USAGE
2286 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2287#endif
2288 return(ret);
2289 }
2290 }
2291 return(xmlXPathNewBoolean(val));
2292}
2293
2294/**
2295 * xmlXPathCacheNewFloat:
2296 * @ctxt: the XPath context
2297 * @val: the double value
2298 *
2299 * This is the cached version of xmlXPathNewFloat().
2300 * Acquires an xmlXPathObjectPtr of type double and of value @val
2301 *
2302 * Returns the created or reused object.
2303 */
2304static xmlXPathObjectPtr
2305xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2306{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002307 if ((ctxt != NULL) && (ctxt->cache)) {
2308 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002309
2310 if ((cache->numberObjs != NULL) &&
2311 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002312 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002313 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002314
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002315 ret = (xmlXPathObjectPtr)
2316 cache->numberObjs->items[--cache->numberObjs->number];
2317 ret->type = XPATH_NUMBER;
2318 ret->floatval = val;
2319#ifdef XP_DEBUG_OBJ_USAGE
2320 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2321#endif
2322 return(ret);
2323 } else if ((cache->miscObjs != NULL) &&
2324 (cache->miscObjs->number != 0))
2325 {
2326 xmlXPathObjectPtr ret;
2327
2328 ret = (xmlXPathObjectPtr)
2329 cache->miscObjs->items[--cache->miscObjs->number];
2330
2331 ret->type = XPATH_NUMBER;
2332 ret->floatval = val;
2333#ifdef XP_DEBUG_OBJ_USAGE
2334 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2335#endif
2336 return(ret);
2337 }
2338 }
2339 return(xmlXPathNewFloat(val));
2340}
2341
2342/**
2343 * xmlXPathCacheConvertString:
2344 * @ctxt: the XPath context
2345 * @val: an XPath object
2346 *
2347 * This is the cached version of xmlXPathConvertString().
2348 * Converts an existing object to its string() equivalent
2349 *
2350 * Returns a created or reused object, the old one is freed (cached)
2351 * (or the operation is done directly on @val)
2352 */
2353
2354static xmlXPathObjectPtr
2355xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002356 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002357
2358 if (val == NULL)
2359 return(xmlXPathCacheNewCString(ctxt, ""));
2360
2361 switch (val->type) {
2362 case XPATH_UNDEFINED:
2363#ifdef DEBUG_EXPR
2364 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2365#endif
2366 break;
2367 case XPATH_NODESET:
2368 case XPATH_XSLT_TREE:
2369 res = xmlXPathCastNodeSetToString(val->nodesetval);
2370 break;
2371 case XPATH_STRING:
2372 return(val);
2373 case XPATH_BOOLEAN:
2374 res = xmlXPathCastBooleanToString(val->boolval);
2375 break;
2376 case XPATH_NUMBER:
2377 res = xmlXPathCastNumberToString(val->floatval);
2378 break;
2379 case XPATH_USERS:
2380 case XPATH_POINT:
2381 case XPATH_RANGE:
2382 case XPATH_LOCATIONSET:
2383 TODO;
2384 break;
2385 }
2386 xmlXPathReleaseObject(ctxt, val);
2387 if (res == NULL)
2388 return(xmlXPathCacheNewCString(ctxt, ""));
2389 return(xmlXPathCacheWrapString(ctxt, res));
2390}
2391
2392/**
2393 * xmlXPathCacheObjectCopy:
2394 * @ctxt: the XPath context
2395 * @val: the original object
2396 *
2397 * This is the cached version of xmlXPathObjectCopy().
2398 * Acquire a copy of a given object
2399 *
2400 * Returns a created or reused created object.
2401 */
2402static xmlXPathObjectPtr
2403xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2404{
2405 if (val == NULL)
2406 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002407
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002408 if (XP_HAS_CACHE(ctxt)) {
2409 switch (val->type) {
2410 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002411 return(xmlXPathCacheWrapNodeSet(ctxt,
2412 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002413 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002414 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002415 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002416 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002417 case XPATH_NUMBER:
2418 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2419 default:
2420 break;
2421 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002422 }
2423 return(xmlXPathObjectCopy(val));
2424}
2425
2426/**
2427 * xmlXPathCacheConvertBoolean:
2428 * @ctxt: the XPath context
2429 * @val: an XPath object
2430 *
2431 * This is the cached version of xmlXPathConvertBoolean().
2432 * Converts an existing object to its boolean() equivalent
2433 *
2434 * Returns a created or reused object, the old one is freed (or the operation
2435 * is done directly on @val)
2436 */
2437static xmlXPathObjectPtr
2438xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2439 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002440
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002441 if (val == NULL)
2442 return(xmlXPathCacheNewBoolean(ctxt, 0));
2443 if (val->type == XPATH_BOOLEAN)
2444 return(val);
2445 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2446 xmlXPathReleaseObject(ctxt, val);
2447 return(ret);
2448}
2449
2450/**
2451 * xmlXPathCacheConvertNumber:
2452 * @ctxt: the XPath context
2453 * @val: an XPath object
2454 *
2455 * This is the cached version of xmlXPathConvertNumber().
2456 * Converts an existing object to its number() equivalent
2457 *
2458 * Returns a created or reused object, the old one is freed (or the operation
2459 * is done directly on @val)
2460 */
2461static xmlXPathObjectPtr
2462xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2463 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002464
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002465 if (val == NULL)
2466 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2467 if (val->type == XPATH_NUMBER)
2468 return(val);
2469 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2470 xmlXPathReleaseObject(ctxt, val);
2471 return(ret);
2472}
2473
2474/************************************************************************
2475 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002476 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002477 * *
2478 ************************************************************************/
2479
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002480/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002481 * xmlXPathSetFrame:
2482 * @ctxt: an XPath parser context
2483 *
2484 * Set the callee evaluation frame
2485 *
2486 * Returns the previous frame value to be restored once done
2487 */
2488static int
2489xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2490 int ret;
2491
2492 if (ctxt == NULL)
2493 return(0);
2494 ret = ctxt->valueFrame;
2495 ctxt->valueFrame = ctxt->valueNr;
2496 return(ret);
2497}
2498
2499/**
2500 * xmlXPathPopFrame:
2501 * @ctxt: an XPath parser context
2502 * @frame: the previous frame value
2503 *
2504 * Remove the callee evaluation frame
2505 */
2506static void
2507xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2508 if (ctxt == NULL)
2509 return;
2510 if (ctxt->valueNr < ctxt->valueFrame) {
2511 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2512 }
2513 ctxt->valueFrame = frame;
2514}
2515
2516/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002517 * valuePop:
2518 * @ctxt: an XPath evaluation context
2519 *
2520 * Pops the top XPath object from the value stack
2521 *
2522 * Returns the XPath object just removed
2523 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002524xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002525valuePop(xmlXPathParserContextPtr ctxt)
2526{
2527 xmlXPathObjectPtr ret;
2528
Daniel Veillarda82b1822004-11-08 16:24:57 +00002529 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002530 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002531
2532 if (ctxt->valueNr <= ctxt->valueFrame) {
2533 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2534 return (NULL);
2535 }
2536
Daniel Veillard1c732d22002-11-30 11:22:59 +00002537 ctxt->valueNr--;
2538 if (ctxt->valueNr > 0)
2539 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2540 else
2541 ctxt->value = NULL;
2542 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002543 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002544 return (ret);
2545}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002546/**
2547 * valuePush:
2548 * @ctxt: an XPath evaluation context
2549 * @value: the XPath object
2550 *
2551 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002552 *
2553 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002554 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002555int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002556valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2557{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002558 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002559 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002560 xmlXPathObjectPtr *tmp;
2561
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002562 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2563 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2564 ctxt->error = XPATH_MEMORY_ERROR;
2565 return (0);
2566 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002567 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2568 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002569 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002570 if (tmp == NULL) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002571 xmlXPathErrMemory(NULL, "pushing value\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08002572 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002573 return (0);
2574 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002575 ctxt->valueMax *= 2;
2576 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002577 }
2578 ctxt->valueTab[ctxt->valueNr] = value;
2579 ctxt->value = value;
2580 return (ctxt->valueNr++);
2581}
Owen Taylor3473f882001-02-23 17:55:21 +00002582
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002583/**
2584 * xmlXPathPopBoolean:
2585 * @ctxt: an XPath parser context
2586 *
2587 * Pops a boolean from the stack, handling conversion if needed.
2588 * Check error with #xmlXPathCheckError.
2589 *
2590 * Returns the boolean
2591 */
2592int
2593xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2594 xmlXPathObjectPtr obj;
2595 int ret;
2596
2597 obj = valuePop(ctxt);
2598 if (obj == NULL) {
2599 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2600 return(0);
2601 }
William M. Brack08171912003-12-29 02:52:11 +00002602 if (obj->type != XPATH_BOOLEAN)
2603 ret = xmlXPathCastToBoolean(obj);
2604 else
2605 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002606 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002607 return(ret);
2608}
2609
2610/**
2611 * xmlXPathPopNumber:
2612 * @ctxt: an XPath parser context
2613 *
2614 * Pops a number from the stack, handling conversion if needed.
2615 * Check error with #xmlXPathCheckError.
2616 *
2617 * Returns the number
2618 */
2619double
2620xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2621 xmlXPathObjectPtr obj;
2622 double ret;
2623
2624 obj = valuePop(ctxt);
2625 if (obj == NULL) {
2626 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2627 return(0);
2628 }
William M. Brack08171912003-12-29 02:52:11 +00002629 if (obj->type != XPATH_NUMBER)
2630 ret = xmlXPathCastToNumber(obj);
2631 else
2632 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002633 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002634 return(ret);
2635}
2636
2637/**
2638 * xmlXPathPopString:
2639 * @ctxt: an XPath parser context
2640 *
2641 * Pops a string from the stack, handling conversion if needed.
2642 * Check error with #xmlXPathCheckError.
2643 *
2644 * Returns the string
2645 */
2646xmlChar *
2647xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2648 xmlXPathObjectPtr obj;
2649 xmlChar * ret;
2650
2651 obj = valuePop(ctxt);
2652 if (obj == NULL) {
2653 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2654 return(NULL);
2655 }
William M. Brack08171912003-12-29 02:52:11 +00002656 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002657 /* TODO: needs refactoring somewhere else */
2658 if (obj->stringval == ret)
2659 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002660 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002661 return(ret);
2662}
2663
2664/**
2665 * xmlXPathPopNodeSet:
2666 * @ctxt: an XPath parser context
2667 *
2668 * Pops a node-set from the stack, handling conversion if needed.
2669 * Check error with #xmlXPathCheckError.
2670 *
2671 * Returns the node-set
2672 */
2673xmlNodeSetPtr
2674xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2675 xmlXPathObjectPtr obj;
2676 xmlNodeSetPtr ret;
2677
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002678 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002679 if (ctxt->value == NULL) {
2680 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2681 return(NULL);
2682 }
2683 if (!xmlXPathStackIsNodeSet(ctxt)) {
2684 xmlXPathSetTypeError(ctxt);
2685 return(NULL);
2686 }
2687 obj = valuePop(ctxt);
2688 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002689#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002690 /* to fix memory leak of not clearing obj->user */
2691 if (obj->boolval && obj->user != NULL)
2692 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002693#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002694 obj->nodesetval = NULL;
2695 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002696 return(ret);
2697}
2698
2699/**
2700 * xmlXPathPopExternal:
2701 * @ctxt: an XPath parser context
2702 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002703 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002704 * Check error with #xmlXPathCheckError.
2705 *
2706 * Returns the object
2707 */
2708void *
2709xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2710 xmlXPathObjectPtr obj;
2711 void * ret;
2712
Daniel Veillarda82b1822004-11-08 16:24:57 +00002713 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002714 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2715 return(NULL);
2716 }
2717 if (ctxt->value->type != XPATH_USERS) {
2718 xmlXPathSetTypeError(ctxt);
2719 return(NULL);
2720 }
2721 obj = valuePop(ctxt);
2722 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002723 obj->user = NULL;
2724 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002725 return(ret);
2726}
2727
Owen Taylor3473f882001-02-23 17:55:21 +00002728/*
2729 * Macros for accessing the content. Those should be used only by the parser,
2730 * and not exported.
2731 *
2732 * Dirty macros, i.e. one need to make assumption on the context to use them
2733 *
2734 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2735 * CUR returns the current xmlChar value, i.e. a 8 bit value
2736 * in ISO-Latin or UTF-8.
2737 * This should be used internally by the parser
2738 * only to compare to ASCII values otherwise it would break when
2739 * running with UTF-8 encoding.
2740 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2741 * to compare on ASCII based substring.
2742 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2743 * strings within the parser.
2744 * CURRENT Returns the current char value, with the full decoding of
2745 * UTF-8 if we are using this mode. It returns an int.
2746 * NEXT Skip to the next character, this does the proper decoding
2747 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2748 * It returns the pointer to the current xmlChar.
2749 */
2750
2751#define CUR (*ctxt->cur)
2752#define SKIP(val) ctxt->cur += (val)
2753#define NXT(val) ctxt->cur[(val)]
2754#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002755#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2756
2757#define COPY_BUF(l,b,i,v) \
2758 if (l == 1) b[i++] = (xmlChar) v; \
2759 else i += xmlCopyChar(l,&b[i],v)
2760
2761#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002762
Daniel Veillard45490ae2008-07-29 09:13:19 +00002763#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002764 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002765
2766#define CURRENT (*ctxt->cur)
2767#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2768
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002769
2770#ifndef DBL_DIG
2771#define DBL_DIG 16
2772#endif
2773#ifndef DBL_EPSILON
2774#define DBL_EPSILON 1E-9
2775#endif
2776
2777#define UPPER_DOUBLE 1E9
2778#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00002779#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002780
2781#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00002782#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002783#define EXPONENT_DIGITS (3 + 2)
2784
2785/**
2786 * xmlXPathFormatNumber:
2787 * @number: number to format
2788 * @buffer: output buffer
2789 * @buffersize: size of output buffer
2790 *
2791 * Convert the number into a string representation.
2792 */
2793static void
2794xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2795{
Daniel Veillardcda96922001-08-21 10:56:31 +00002796 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002797 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002798 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002799 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002800 break;
2801 case -1:
2802 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002803 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002804 break;
2805 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002806 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002807 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002808 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002809 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002810 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002811 } else if (number == ((int) number)) {
2812 char work[30];
2813 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002814 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002815
2816 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002817 if (value == 0) {
2818 *ptr++ = '0';
2819 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002820 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002821 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002822 while ((*cur) && (ptr - buffer < buffersize)) {
2823 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002824 }
2825 }
2826 if (ptr - buffer < buffersize) {
2827 *ptr = 0;
2828 } else if (buffersize > 0) {
2829 ptr--;
2830 *ptr = 0;
2831 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002832 } else {
William M. Brackca797882007-05-11 14:45:53 +00002833 /*
2834 For the dimension of work,
2835 DBL_DIG is number of significant digits
2836 EXPONENT is only needed for "scientific notation"
2837 3 is sign, decimal point, and terminating zero
2838 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2839 Note that this dimension is slightly (a few characters)
2840 larger than actually necessary.
2841 */
2842 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002843 int integer_place, fraction_place;
2844 char *ptr;
2845 char *after_fraction;
2846 double absolute_value;
2847 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002848
Bjorn Reese70a9da52001-04-21 16:57:29 +00002849 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002850
Bjorn Reese70a9da52001-04-21 16:57:29 +00002851 /*
2852 * First choose format - scientific or regular floating point.
2853 * In either case, result is in work, and after_fraction points
2854 * just past the fractional part.
2855 */
2856 if ( ((absolute_value > UPPER_DOUBLE) ||
2857 (absolute_value < LOWER_DOUBLE)) &&
2858 (absolute_value != 0.0) ) {
2859 /* Use scientific notation */
2860 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2861 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002862 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002863 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002864 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002865
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002866 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002867 else {
2868 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00002869 if (absolute_value > 0.0) {
2870 integer_place = (int)log10(absolute_value);
2871 if (integer_place > 0)
2872 fraction_place = DBL_DIG - integer_place - 1;
2873 else
2874 fraction_place = DBL_DIG - integer_place;
2875 } else {
2876 fraction_place = 1;
2877 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002878 size = snprintf(work, sizeof(work), "%0.*f",
2879 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002880 }
2881
Bjorn Reese70a9da52001-04-21 16:57:29 +00002882 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00002883 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002884 ptr = after_fraction;
2885 while (*(--ptr) == '0')
2886 ;
2887 if (*ptr != '.')
2888 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002889 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002890
2891 /* Finally copy result back to caller */
2892 size = strlen(work) + 1;
2893 if (size > buffersize) {
2894 work[buffersize - 1] = 0;
2895 size = buffersize;
2896 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002897 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002898 }
2899 break;
2900 }
2901}
2902
Owen Taylor3473f882001-02-23 17:55:21 +00002903
2904/************************************************************************
2905 * *
2906 * Routines to handle NodeSets *
2907 * *
2908 ************************************************************************/
2909
2910/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002911 * xmlXPathOrderDocElems:
2912 * @doc: an input document
2913 *
2914 * Call this routine to speed up XPath computation on static documents.
2915 * This stamps all the element nodes with the document order
2916 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002917 * field, the value stored is actually - the node number (starting at -1)
2918 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002919 *
William M. Brack08171912003-12-29 02:52:11 +00002920 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002921 * of error.
2922 */
2923long
2924xmlXPathOrderDocElems(xmlDocPtr doc) {
2925 long count = 0;
2926 xmlNodePtr cur;
2927
2928 if (doc == NULL)
2929 return(-1);
2930 cur = doc->children;
2931 while (cur != NULL) {
2932 if (cur->type == XML_ELEMENT_NODE) {
2933 cur->content = (void *) (-(++count));
2934 if (cur->children != NULL) {
2935 cur = cur->children;
2936 continue;
2937 }
2938 }
2939 if (cur->next != NULL) {
2940 cur = cur->next;
2941 continue;
2942 }
2943 do {
2944 cur = cur->parent;
2945 if (cur == NULL)
2946 break;
2947 if (cur == (xmlNodePtr) doc) {
2948 cur = NULL;
2949 break;
2950 }
2951 if (cur->next != NULL) {
2952 cur = cur->next;
2953 break;
2954 }
2955 } while (cur != NULL);
2956 }
2957 return(count);
2958}
2959
2960/**
Owen Taylor3473f882001-02-23 17:55:21 +00002961 * xmlXPathCmpNodes:
2962 * @node1: the first node
2963 * @node2: the second node
2964 *
2965 * Compare two nodes w.r.t document order
2966 *
2967 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002968 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002969 */
2970int
2971xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2972 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002973 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002974 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002975 xmlNodePtr cur, root;
2976
2977 if ((node1 == NULL) || (node2 == NULL))
2978 return(-2);
2979 /*
2980 * a couple of optimizations which will avoid computations in most cases
2981 */
William M. Brackee0b9822007-03-07 08:15:01 +00002982 if (node1 == node2) /* trivial case */
2983 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00002984 if (node1->type == XML_ATTRIBUTE_NODE) {
2985 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002986 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002987 node1 = node1->parent;
2988 }
2989 if (node2->type == XML_ATTRIBUTE_NODE) {
2990 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002991 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002992 node2 = node2->parent;
2993 }
2994 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002995 if (attr1 == attr2) {
2996 /* not required, but we keep attributes in order */
2997 if (attr1 != 0) {
2998 cur = attrNode2->prev;
2999 while (cur != NULL) {
3000 if (cur == attrNode1)
3001 return (1);
3002 cur = cur->prev;
3003 }
3004 return (-1);
3005 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003006 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00003007 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003008 if (attr2 == 1)
3009 return(1);
3010 return(-1);
3011 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003012 if ((node1->type == XML_NAMESPACE_DECL) ||
3013 (node2->type == XML_NAMESPACE_DECL))
3014 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003015 if (node1 == node2->prev)
3016 return(1);
3017 if (node1 == node2->next)
3018 return(-1);
3019
3020 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003021 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003022 */
3023 if ((node1->type == XML_ELEMENT_NODE) &&
3024 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003025 (0 > (long) node1->content) &&
3026 (0 > (long) node2->content) &&
3027 (node1->doc == node2->doc)) {
3028 long l1, l2;
3029
3030 l1 = -((long) node1->content);
3031 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003032 if (l1 < l2)
3033 return(1);
3034 if (l1 > l2)
3035 return(-1);
3036 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003037
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003038 /*
Owen Taylor3473f882001-02-23 17:55:21 +00003039 * compute depth to root
3040 */
3041 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3042 if (cur == node1)
3043 return(1);
3044 depth2++;
3045 }
3046 root = cur;
3047 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3048 if (cur == node2)
3049 return(-1);
3050 depth1++;
3051 }
3052 /*
3053 * Distinct document (or distinct entities :-( ) case.
3054 */
3055 if (root != cur) {
3056 return(-2);
3057 }
3058 /*
3059 * get the nearest common ancestor.
3060 */
3061 while (depth1 > depth2) {
3062 depth1--;
3063 node1 = node1->parent;
3064 }
3065 while (depth2 > depth1) {
3066 depth2--;
3067 node2 = node2->parent;
3068 }
3069 while (node1->parent != node2->parent) {
3070 node1 = node1->parent;
3071 node2 = node2->parent;
3072 /* should not happen but just in case ... */
3073 if ((node1 == NULL) || (node2 == NULL))
3074 return(-2);
3075 }
3076 /*
3077 * Find who's first.
3078 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003079 if (node1 == node2->prev)
3080 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003081 if (node1 == node2->next)
3082 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003083 /*
3084 * Speedup using document order if availble.
3085 */
3086 if ((node1->type == XML_ELEMENT_NODE) &&
3087 (node2->type == XML_ELEMENT_NODE) &&
3088 (0 > (long) node1->content) &&
3089 (0 > (long) node2->content) &&
3090 (node1->doc == node2->doc)) {
3091 long l1, l2;
3092
3093 l1 = -((long) node1->content);
3094 l2 = -((long) node2->content);
3095 if (l1 < l2)
3096 return(1);
3097 if (l1 > l2)
3098 return(-1);
3099 }
3100
Owen Taylor3473f882001-02-23 17:55:21 +00003101 for (cur = node1->next;cur != NULL;cur = cur->next)
3102 if (cur == node2)
3103 return(1);
3104 return(-1); /* assume there is no sibling list corruption */
3105}
3106
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003107#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003108/**
3109 * xmlXPathCmpNodesExt:
3110 * @node1: the first node
3111 * @node2: the second node
3112 *
3113 * Compare two nodes w.r.t document order.
3114 * This one is optimized for handling of non-element nodes.
3115 *
3116 * Returns -2 in case of error 1 if first point < second point, 0 if
3117 * it's the same node, -1 otherwise
3118 */
3119static int
3120xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3121 int depth1, depth2;
3122 int misc = 0, precedence1 = 0, precedence2 = 0;
3123 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3124 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003125 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003126
3127 if ((node1 == NULL) || (node2 == NULL))
3128 return(-2);
3129
3130 if (node1 == node2)
3131 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00003132
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003133 /*
3134 * a couple of optimizations which will avoid computations in most cases
Daniel Veillard45490ae2008-07-29 09:13:19 +00003135 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003136 switch (node1->type) {
3137 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003138 if (node2->type == XML_ELEMENT_NODE) {
3139 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3140 (0 > (long) node2->content) &&
3141 (node1->doc == node2->doc))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003142 {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003143 l1 = -((long) node1->content);
3144 l2 = -((long) node2->content);
3145 if (l1 < l2)
3146 return(1);
3147 if (l1 > l2)
3148 return(-1);
3149 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003150 goto turtle_comparison;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003151 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003152 break;
3153 case XML_ATTRIBUTE_NODE:
3154 precedence1 = 1; /* element is owner */
3155 miscNode1 = node1;
3156 node1 = node1->parent;
3157 misc = 1;
3158 break;
3159 case XML_TEXT_NODE:
3160 case XML_CDATA_SECTION_NODE:
3161 case XML_COMMENT_NODE:
3162 case XML_PI_NODE: {
3163 miscNode1 = node1;
3164 /*
3165 * Find nearest element node.
Daniel Veillard45490ae2008-07-29 09:13:19 +00003166 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003167 if (node1->prev != NULL) {
3168 do {
3169 node1 = node1->prev;
3170 if (node1->type == XML_ELEMENT_NODE) {
3171 precedence1 = 3; /* element in prev-sibl axis */
3172 break;
3173 }
3174 if (node1->prev == NULL) {
3175 precedence1 = 2; /* element is parent */
3176 /*
3177 * URGENT TODO: Are there any cases, where the
3178 * parent of such a node is not an element node?
3179 */
3180 node1 = node1->parent;
3181 break;
3182 }
3183 } while (1);
3184 } else {
3185 precedence1 = 2; /* element is parent */
3186 node1 = node1->parent;
3187 }
William M. Brack31700e62007-06-13 20:33:02 +00003188 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3189 (0 <= (long) node1->content)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003190 /*
3191 * Fallback for whatever case.
3192 */
3193 node1 = miscNode1;
3194 precedence1 = 0;
3195 } else
3196 misc = 1;
3197 }
3198 break;
3199 case XML_NAMESPACE_DECL:
3200 /*
3201 * TODO: why do we return 1 for namespace nodes?
3202 */
3203 return(1);
3204 default:
3205 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003206 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003207 switch (node2->type) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003208 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003209 break;
3210 case XML_ATTRIBUTE_NODE:
3211 precedence2 = 1; /* element is owner */
3212 miscNode2 = node2;
3213 node2 = node2->parent;
3214 misc = 1;
3215 break;
3216 case XML_TEXT_NODE:
3217 case XML_CDATA_SECTION_NODE:
3218 case XML_COMMENT_NODE:
3219 case XML_PI_NODE: {
3220 miscNode2 = node2;
3221 if (node2->prev != NULL) {
3222 do {
3223 node2 = node2->prev;
3224 if (node2->type == XML_ELEMENT_NODE) {
3225 precedence2 = 3; /* element in prev-sibl axis */
3226 break;
3227 }
3228 if (node2->prev == NULL) {
3229 precedence2 = 2; /* element is parent */
3230 node2 = node2->parent;
3231 break;
3232 }
3233 } while (1);
3234 } else {
3235 precedence2 = 2; /* element is parent */
3236 node2 = node2->parent;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003237 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003238 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3239 (0 <= (long) node1->content))
3240 {
3241 node2 = miscNode2;
3242 precedence2 = 0;
3243 } else
3244 misc = 1;
3245 }
3246 break;
3247 case XML_NAMESPACE_DECL:
3248 return(1);
3249 default:
3250 break;
3251 }
3252 if (misc) {
3253 if (node1 == node2) {
3254 if (precedence1 == precedence2) {
3255 /*
3256 * The ugly case; but normally there aren't many
3257 * adjacent non-element nodes around.
3258 */
3259 cur = miscNode2->prev;
3260 while (cur != NULL) {
3261 if (cur == miscNode1)
3262 return(1);
3263 if (cur->type == XML_ELEMENT_NODE)
3264 return(-1);
3265 cur = cur->prev;
3266 }
3267 return (-1);
3268 } else {
3269 /*
3270 * Evaluate based on higher precedence wrt to the element.
3271 * TODO: This assumes attributes are sorted before content.
3272 * Is this 100% correct?
3273 */
3274 if (precedence1 < precedence2)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003275 return(1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003276 else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003277 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003278 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003279 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003280 /*
3281 * Special case: One of the helper-elements is contained by the other.
3282 * <foo>
3283 * <node2>
3284 * <node1>Text-1(precedence1 == 2)</node1>
3285 * </node2>
3286 * Text-6(precedence2 == 3)
3287 * </foo>
Daniel Veillard45490ae2008-07-29 09:13:19 +00003288 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003289 if ((precedence2 == 3) && (precedence1 > 1)) {
3290 cur = node1->parent;
3291 while (cur) {
3292 if (cur == node2)
3293 return(1);
3294 cur = cur->parent;
3295 }
3296 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003297 if ((precedence1 == 3) && (precedence2 > 1)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003298 cur = node2->parent;
3299 while (cur) {
3300 if (cur == node1)
3301 return(-1);
3302 cur = cur->parent;
3303 }
3304 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003305 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003306
3307 /*
3308 * Speedup using document order if availble.
3309 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003310 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003311 (node2->type == XML_ELEMENT_NODE) &&
3312 (0 > (long) node1->content) &&
3313 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003314 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003315
3316 l1 = -((long) node1->content);
3317 l2 = -((long) node2->content);
3318 if (l1 < l2)
3319 return(1);
3320 if (l1 > l2)
3321 return(-1);
3322 }
3323
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003324turtle_comparison:
3325
3326 if (node1 == node2->prev)
3327 return(1);
3328 if (node1 == node2->next)
3329 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003330 /*
3331 * compute depth to root
3332 */
3333 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3334 if (cur == node1)
3335 return(1);
3336 depth2++;
3337 }
3338 root = cur;
3339 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3340 if (cur == node2)
3341 return(-1);
3342 depth1++;
3343 }
3344 /*
3345 * Distinct document (or distinct entities :-( ) case.
3346 */
3347 if (root != cur) {
3348 return(-2);
3349 }
3350 /*
3351 * get the nearest common ancestor.
3352 */
3353 while (depth1 > depth2) {
3354 depth1--;
3355 node1 = node1->parent;
3356 }
3357 while (depth2 > depth1) {
3358 depth2--;
3359 node2 = node2->parent;
3360 }
3361 while (node1->parent != node2->parent) {
3362 node1 = node1->parent;
3363 node2 = node2->parent;
3364 /* should not happen but just in case ... */
3365 if ((node1 == NULL) || (node2 == NULL))
3366 return(-2);
3367 }
3368 /*
3369 * Find who's first.
3370 */
3371 if (node1 == node2->prev)
3372 return(1);
3373 if (node1 == node2->next)
3374 return(-1);
3375 /*
3376 * Speedup using document order if availble.
3377 */
3378 if ((node1->type == XML_ELEMENT_NODE) &&
3379 (node2->type == XML_ELEMENT_NODE) &&
3380 (0 > (long) node1->content) &&
3381 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003382 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003383
3384 l1 = -((long) node1->content);
3385 l2 = -((long) node2->content);
3386 if (l1 < l2)
3387 return(1);
3388 if (l1 > l2)
3389 return(-1);
3390 }
3391
3392 for (cur = node1->next;cur != NULL;cur = cur->next)
3393 if (cur == node2)
3394 return(1);
3395 return(-1); /* assume there is no sibling list corruption */
3396}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003397#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003398
Owen Taylor3473f882001-02-23 17:55:21 +00003399/**
3400 * xmlXPathNodeSetSort:
3401 * @set: the node set
3402 *
3403 * Sort the node set in document order
3404 */
3405void
3406xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Vojtech Fried3e031b72012-08-24 16:52:44 +08003407#ifndef WITH_TIM_SORT
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003408 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003409 xmlNodePtr tmp;
Vojtech Fried3e031b72012-08-24 16:52:44 +08003410#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003411
3412 if (set == NULL)
3413 return;
3414
Vojtech Fried3e031b72012-08-24 16:52:44 +08003415#ifndef WITH_TIM_SORT
3416 /*
3417 * Use the old Shell's sort implementation to sort the node-set
3418 * Timsort ought to be quite faster
3419 */
Owen Taylor3473f882001-02-23 17:55:21 +00003420 len = set->nodeNr;
3421 for (incr = len / 2; incr > 0; incr /= 2) {
3422 for (i = incr; i < len; i++) {
3423 j = i - incr;
3424 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003425#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003426 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3427 set->nodeTab[j + incr]) == -1)
3428#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003429 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003430 set->nodeTab[j + incr]) == -1)
3431#endif
3432 {
Owen Taylor3473f882001-02-23 17:55:21 +00003433 tmp = set->nodeTab[j];
3434 set->nodeTab[j] = set->nodeTab[j + incr];
3435 set->nodeTab[j + incr] = tmp;
3436 j -= incr;
3437 } else
3438 break;
3439 }
3440 }
3441 }
Vojtech Fried3e031b72012-08-24 16:52:44 +08003442#else /* WITH_TIM_SORT */
3443 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3444#endif /* WITH_TIM_SORT */
Owen Taylor3473f882001-02-23 17:55:21 +00003445}
3446
3447#define XML_NODESET_DEFAULT 10
3448/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003449 * xmlXPathNodeSetDupNs:
3450 * @node: the parent node of the namespace XPath node
3451 * @ns: the libxml namespace declaration node.
3452 *
3453 * Namespace node in libxml don't match the XPath semantic. In a node set
3454 * the namespace nodes are duplicated and the next pointer is set to the
3455 * parent node in the XPath semantic.
3456 *
3457 * Returns the newly created object.
3458 */
3459static xmlNodePtr
3460xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3461 xmlNsPtr cur;
3462
3463 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3464 return(NULL);
3465 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3466 return((xmlNodePtr) ns);
3467
3468 /*
3469 * Allocate a new Namespace and fill the fields.
3470 */
3471 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3472 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003473 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003474 return(NULL);
3475 }
3476 memset(cur, 0, sizeof(xmlNs));
3477 cur->type = XML_NAMESPACE_DECL;
3478 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003479 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003480 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003481 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003482 cur->next = (xmlNsPtr) node;
3483 return((xmlNodePtr) cur);
3484}
3485
3486/**
3487 * xmlXPathNodeSetFreeNs:
3488 * @ns: the XPath namespace node found in a nodeset.
3489 *
William M. Brack08171912003-12-29 02:52:11 +00003490 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003491 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003492 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003493 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003494void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003495xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3496 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3497 return;
3498
3499 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3500 if (ns->href != NULL)
3501 xmlFree((xmlChar *)ns->href);
3502 if (ns->prefix != NULL)
3503 xmlFree((xmlChar *)ns->prefix);
3504 xmlFree(ns);
3505 }
3506}
3507
3508/**
Owen Taylor3473f882001-02-23 17:55:21 +00003509 * xmlXPathNodeSetCreate:
3510 * @val: an initial xmlNodePtr, or NULL
3511 *
3512 * Create a new xmlNodeSetPtr of type double and of value @val
3513 *
3514 * Returns the newly created object.
3515 */
3516xmlNodeSetPtr
3517xmlXPathNodeSetCreate(xmlNodePtr val) {
3518 xmlNodeSetPtr ret;
3519
3520 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3521 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003522 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003523 return(NULL);
3524 }
3525 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3526 if (val != NULL) {
3527 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3528 sizeof(xmlNodePtr));
3529 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003530 xmlXPathErrMemory(NULL, "creating nodeset\n");
3531 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003532 return(NULL);
3533 }
3534 memset(ret->nodeTab, 0 ,
3535 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3536 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003537 if (val->type == XML_NAMESPACE_DECL) {
3538 xmlNsPtr ns = (xmlNsPtr) val;
3539
3540 ret->nodeTab[ret->nodeNr++] =
3541 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3542 } else
3543 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003544 }
3545 return(ret);
3546}
3547
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003548/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003549 * xmlXPathNodeSetCreateSize:
3550 * @size: the initial size of the set
3551 *
3552 * Create a new xmlNodeSetPtr of type double and of value @val
3553 *
3554 * Returns the newly created object.
3555 */
3556static xmlNodeSetPtr
3557xmlXPathNodeSetCreateSize(int size) {
3558 xmlNodeSetPtr ret;
3559
3560 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3561 if (ret == NULL) {
3562 xmlXPathErrMemory(NULL, "creating nodeset\n");
3563 return(NULL);
3564 }
3565 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3566 if (size < XML_NODESET_DEFAULT)
3567 size = XML_NODESET_DEFAULT;
3568 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3569 if (ret->nodeTab == NULL) {
3570 xmlXPathErrMemory(NULL, "creating nodeset\n");
3571 xmlFree(ret);
3572 return(NULL);
3573 }
3574 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003575 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003576 return(ret);
3577}
3578
3579/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003580 * xmlXPathNodeSetContains:
3581 * @cur: the node-set
3582 * @val: the node
3583 *
3584 * checks whether @cur contains @val
3585 *
3586 * Returns true (1) if @cur contains @val, false (0) otherwise
3587 */
3588int
3589xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3590 int i;
3591
Daniel Veillarda82b1822004-11-08 16:24:57 +00003592 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003593 if (val->type == XML_NAMESPACE_DECL) {
3594 for (i = 0; i < cur->nodeNr; i++) {
3595 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3596 xmlNsPtr ns1, ns2;
3597
3598 ns1 = (xmlNsPtr) val;
3599 ns2 = (xmlNsPtr) cur->nodeTab[i];
3600 if (ns1 == ns2)
3601 return(1);
3602 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3603 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3604 return(1);
3605 }
3606 }
3607 } else {
3608 for (i = 0; i < cur->nodeNr; i++) {
3609 if (cur->nodeTab[i] == val)
3610 return(1);
3611 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003612 }
3613 return(0);
3614}
3615
3616/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003617 * xmlXPathNodeSetAddNs:
3618 * @cur: the initial node set
3619 * @node: the hosting node
3620 * @ns: a the namespace node
3621 *
3622 * add a new namespace node to an existing NodeSet
3623 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003624void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003625xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3626 int i;
3627
Daniel Veillard45490ae2008-07-29 09:13:19 +00003628
Daniel Veillarda82b1822004-11-08 16:24:57 +00003629 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3630 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003631 (node->type != XML_ELEMENT_NODE))
3632 return;
3633
William M. Brack08171912003-12-29 02:52:11 +00003634 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003635 /*
William M. Brack08171912003-12-29 02:52:11 +00003636 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003637 */
3638 for (i = 0;i < cur->nodeNr;i++) {
3639 if ((cur->nodeTab[i] != NULL) &&
3640 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003641 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003642 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3643 return;
3644 }
3645
3646 /*
3647 * grow the nodeTab if needed
3648 */
3649 if (cur->nodeMax == 0) {
3650 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3651 sizeof(xmlNodePtr));
3652 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003653 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003654 return;
3655 }
3656 memset(cur->nodeTab, 0 ,
3657 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3658 cur->nodeMax = XML_NODESET_DEFAULT;
3659 } else if (cur->nodeNr == cur->nodeMax) {
3660 xmlNodePtr *temp;
3661
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003662 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3663 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3664 return;
3665 }
Chris Evansd7958b22011-03-23 08:13:06 +08003666 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003667 sizeof(xmlNodePtr));
3668 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003669 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003670 return;
3671 }
Chris Evansd7958b22011-03-23 08:13:06 +08003672 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003673 cur->nodeTab = temp;
3674 }
3675 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3676}
3677
3678/**
Owen Taylor3473f882001-02-23 17:55:21 +00003679 * xmlXPathNodeSetAdd:
3680 * @cur: the initial node set
3681 * @val: a new xmlNodePtr
3682 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003683 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003684 */
3685void
3686xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3687 int i;
3688
Daniel Veillarda82b1822004-11-08 16:24:57 +00003689 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003690
William M. Brack08171912003-12-29 02:52:11 +00003691 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003692 /*
William M. Brack08171912003-12-29 02:52:11 +00003693 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003694 */
3695 for (i = 0;i < cur->nodeNr;i++)
3696 if (cur->nodeTab[i] == val) return;
3697
3698 /*
3699 * grow the nodeTab if needed
3700 */
3701 if (cur->nodeMax == 0) {
3702 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3703 sizeof(xmlNodePtr));
3704 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003705 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003706 return;
3707 }
3708 memset(cur->nodeTab, 0 ,
3709 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3710 cur->nodeMax = XML_NODESET_DEFAULT;
3711 } else if (cur->nodeNr == cur->nodeMax) {
3712 xmlNodePtr *temp;
3713
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003714 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3715 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3716 return;
3717 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003718 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003719 sizeof(xmlNodePtr));
3720 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003721 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003722 return;
3723 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003724 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003725 cur->nodeTab = temp;
3726 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003727 if (val->type == XML_NAMESPACE_DECL) {
3728 xmlNsPtr ns = (xmlNsPtr) val;
3729
Daniel Veillard45490ae2008-07-29 09:13:19 +00003730 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003731 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3732 } else
3733 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003734}
3735
3736/**
3737 * xmlXPathNodeSetAddUnique:
3738 * @cur: the initial node set
3739 * @val: a new xmlNodePtr
3740 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003741 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003742 * when we are sure the node is not already in the set.
3743 */
3744void
3745xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003746 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003747
William M. Brack08171912003-12-29 02:52:11 +00003748 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003749 /*
3750 * grow the nodeTab if needed
3751 */
3752 if (cur->nodeMax == 0) {
3753 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3754 sizeof(xmlNodePtr));
3755 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003756 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003757 return;
3758 }
3759 memset(cur->nodeTab, 0 ,
3760 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3761 cur->nodeMax = XML_NODESET_DEFAULT;
3762 } else if (cur->nodeNr == cur->nodeMax) {
3763 xmlNodePtr *temp;
3764
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003765 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3766 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3767 return;
3768 }
Chris Evansd7958b22011-03-23 08:13:06 +08003769 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003770 sizeof(xmlNodePtr));
3771 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003772 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003773 return;
3774 }
3775 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003776 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003777 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003778 if (val->type == XML_NAMESPACE_DECL) {
3779 xmlNsPtr ns = (xmlNsPtr) val;
3780
Daniel Veillard45490ae2008-07-29 09:13:19 +00003781 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003782 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3783 } else
3784 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003785}
3786
3787/**
3788 * xmlXPathNodeSetMerge:
3789 * @val1: the first NodeSet or NULL
3790 * @val2: the second NodeSet
3791 *
3792 * Merges two nodesets, all nodes from @val2 are added to @val1
3793 * if @val1 is NULL, a new set is created and copied from @val2
3794 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003795 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003796 */
3797xmlNodeSetPtr
3798xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003799 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003800 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003801
3802 if (val2 == NULL) return(val1);
3803 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003804 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003805 if (val1 == NULL)
3806 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003807#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003808 /*
3809 * TODO: The optimization won't work in every case, since
3810 * those nasty namespace nodes need to be added with
3811 * xmlXPathNodeSetDupNs() to the set; thus a pure
3812 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003813 * If there was a flag on the nodesetval, indicating that
3814 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003815 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003816 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003817 * Optimization: Create an equally sized node-set
3818 * and memcpy the content.
3819 */
3820 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3821 if (val1 == NULL)
3822 return(NULL);
3823 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003824 if (val2->nodeNr == 1)
3825 *(val1->nodeTab) = *(val2->nodeTab);
3826 else {
3827 memcpy(val1->nodeTab, val2->nodeTab,
3828 val2->nodeNr * sizeof(xmlNodePtr));
3829 }
3830 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003831 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003832 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003833#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003834 }
3835
William M. Brack08171912003-12-29 02:52:11 +00003836 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003837 initNr = val1->nodeNr;
3838
3839 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003840 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003841 /*
William M. Brack08171912003-12-29 02:52:11 +00003842 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003843 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003844 skip = 0;
3845 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003846 n1 = val1->nodeTab[j];
3847 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003848 skip = 1;
3849 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003850 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003851 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003852 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3853 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3854 ((xmlNsPtr) n2)->prefix)))
3855 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003856 skip = 1;
3857 break;
3858 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003859 }
3860 }
3861 if (skip)
3862 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003863
3864 /*
3865 * grow the nodeTab if needed
3866 */
3867 if (val1->nodeMax == 0) {
3868 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3869 sizeof(xmlNodePtr));
3870 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003871 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003872 return(NULL);
3873 }
3874 memset(val1->nodeTab, 0 ,
3875 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3876 val1->nodeMax = XML_NODESET_DEFAULT;
3877 } else if (val1->nodeNr == val1->nodeMax) {
3878 xmlNodePtr *temp;
3879
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003880 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3881 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3882 return(NULL);
3883 }
Chris Evansd7958b22011-03-23 08:13:06 +08003884 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003885 sizeof(xmlNodePtr));
3886 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003887 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003888 return(NULL);
3889 }
3890 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003891 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003892 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003893 if (n2->type == XML_NAMESPACE_DECL) {
3894 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003895
3896 val1->nodeTab[val1->nodeNr++] =
3897 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3898 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003899 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003900 }
3901
3902 return(val1);
3903}
3904
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003905
3906/**
3907 * xmlXPathNodeSetMergeAndClear:
3908 * @set1: the first NodeSet or NULL
3909 * @set2: the second NodeSet
3910 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3911 *
3912 * Merges two nodesets, all nodes from @set2 are added to @set1
3913 * if @set1 is NULL, a new set is created and copied from @set2.
3914 * Checks for duplicate nodes. Clears set2.
3915 *
3916 * Returns @set1 once extended or NULL in case of error.
3917 */
3918static xmlNodeSetPtr
3919xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3920 int hasNullEntries)
3921{
3922 if ((set1 == NULL) && (hasNullEntries == 0)) {
3923 /*
3924 * Note that doing a memcpy of the list, namespace nodes are
3925 * just assigned to set1, since set2 is cleared anyway.
3926 */
3927 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3928 if (set1 == NULL)
3929 return(NULL);
3930 if (set2->nodeNr != 0) {
3931 memcpy(set1->nodeTab, set2->nodeTab,
3932 set2->nodeNr * sizeof(xmlNodePtr));
3933 set1->nodeNr = set2->nodeNr;
3934 }
3935 } else {
3936 int i, j, initNbSet1;
3937 xmlNodePtr n1, n2;
3938
3939 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003940 set1 = xmlXPathNodeSetCreate(NULL);
3941 if (set1 == NULL)
3942 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003943
Daniel Veillard45490ae2008-07-29 09:13:19 +00003944 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003945 for (i = 0;i < set2->nodeNr;i++) {
3946 n2 = set2->nodeTab[i];
3947 /*
3948 * Skip NULLed entries.
3949 */
3950 if (n2 == NULL)
3951 continue;
3952 /*
3953 * Skip duplicates.
3954 */
3955 for (j = 0; j < initNbSet1; j++) {
3956 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003957 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003958 goto skip_node;
3959 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3960 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003961 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003962 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3963 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3964 ((xmlNsPtr) n2)->prefix)))
3965 {
3966 /*
3967 * Free the namespace node.
3968 */
3969 set2->nodeTab[i] = NULL;
3970 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3971 goto skip_node;
3972 }
3973 }
3974 }
3975 /*
3976 * grow the nodeTab if needed
3977 */
3978 if (set1->nodeMax == 0) {
3979 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3980 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3981 if (set1->nodeTab == NULL) {
3982 xmlXPathErrMemory(NULL, "merging nodeset\n");
3983 return(NULL);
3984 }
3985 memset(set1->nodeTab, 0,
3986 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3987 set1->nodeMax = XML_NODESET_DEFAULT;
3988 } else if (set1->nodeNr >= set1->nodeMax) {
3989 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003990
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003991 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3992 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3993 return(NULL);
3994 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003995 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08003996 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003997 if (temp == NULL) {
3998 xmlXPathErrMemory(NULL, "merging nodeset\n");
3999 return(NULL);
4000 }
4001 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004002 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004003 }
4004 if (n2->type == XML_NAMESPACE_DECL) {
4005 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004006
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004007 set1->nodeTab[set1->nodeNr++] =
4008 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
4009 } else
4010 set1->nodeTab[set1->nodeNr++] = n2;
4011skip_node:
4012 {}
4013 }
4014 }
4015 set2->nodeNr = 0;
4016 return(set1);
4017}
4018
4019/**
4020 * xmlXPathNodeSetMergeAndClearNoDupls:
4021 * @set1: the first NodeSet or NULL
4022 * @set2: the second NodeSet
4023 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4024 *
4025 * Merges two nodesets, all nodes from @set2 are added to @set1
4026 * if @set1 is NULL, a new set is created and copied from @set2.
4027 * Doesn't chack for duplicate nodes. Clears set2.
4028 *
4029 * Returns @set1 once extended or NULL in case of error.
4030 */
4031static xmlNodeSetPtr
4032xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4033 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004034{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004035 if (set2 == NULL)
4036 return(set1);
4037 if ((set1 == NULL) && (hasNullEntries == 0)) {
4038 /*
4039 * Note that doing a memcpy of the list, namespace nodes are
4040 * just assigned to set1, since set2 is cleared anyway.
4041 */
4042 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4043 if (set1 == NULL)
4044 return(NULL);
4045 if (set2->nodeNr != 0) {
4046 memcpy(set1->nodeTab, set2->nodeTab,
4047 set2->nodeNr * sizeof(xmlNodePtr));
4048 set1->nodeNr = set2->nodeNr;
4049 }
4050 } else {
4051 int i;
4052 xmlNodePtr n2;
4053
4054 if (set1 == NULL)
4055 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004056 if (set1 == NULL)
4057 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004058
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004059 for (i = 0;i < set2->nodeNr;i++) {
4060 n2 = set2->nodeTab[i];
4061 /*
4062 * Skip NULLed entries.
4063 */
4064 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004065 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004066 if (set1->nodeMax == 0) {
4067 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4068 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4069 if (set1->nodeTab == NULL) {
4070 xmlXPathErrMemory(NULL, "merging nodeset\n");
4071 return(NULL);
4072 }
4073 memset(set1->nodeTab, 0,
4074 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4075 set1->nodeMax = XML_NODESET_DEFAULT;
4076 } else if (set1->nodeNr >= set1->nodeMax) {
4077 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004078
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004079 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4080 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4081 return(NULL);
4082 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004083 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004084 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004085 if (temp == NULL) {
4086 xmlXPathErrMemory(NULL, "merging nodeset\n");
4087 return(NULL);
4088 }
4089 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004090 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004091 }
4092 set1->nodeTab[set1->nodeNr++] = n2;
4093 }
4094 }
4095 set2->nodeNr = 0;
4096 return(set1);
4097}
Daniel Veillard75be0132002-03-13 10:03:35 +00004098
4099/**
Owen Taylor3473f882001-02-23 17:55:21 +00004100 * xmlXPathNodeSetDel:
4101 * @cur: the initial node set
4102 * @val: an xmlNodePtr
4103 *
4104 * Removes an xmlNodePtr from an existing NodeSet
4105 */
4106void
4107xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4108 int i;
4109
4110 if (cur == NULL) return;
4111 if (val == NULL) return;
4112
4113 /*
William M. Brack08171912003-12-29 02:52:11 +00004114 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004115 */
4116 for (i = 0;i < cur->nodeNr;i++)
4117 if (cur->nodeTab[i] == val) break;
4118
William M. Brack08171912003-12-29 02:52:11 +00004119 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004120#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004121 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004122 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4123 val->name);
4124#endif
4125 return;
4126 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004127 if ((cur->nodeTab[i] != NULL) &&
4128 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4129 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004130 cur->nodeNr--;
4131 for (;i < cur->nodeNr;i++)
4132 cur->nodeTab[i] = cur->nodeTab[i + 1];
4133 cur->nodeTab[cur->nodeNr] = NULL;
4134}
4135
4136/**
4137 * xmlXPathNodeSetRemove:
4138 * @cur: the initial node set
4139 * @val: the index to remove
4140 *
4141 * Removes an entry from an existing NodeSet list.
4142 */
4143void
4144xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4145 if (cur == NULL) return;
4146 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004147 if ((cur->nodeTab[val] != NULL) &&
4148 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4149 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004150 cur->nodeNr--;
4151 for (;val < cur->nodeNr;val++)
4152 cur->nodeTab[val] = cur->nodeTab[val + 1];
4153 cur->nodeTab[cur->nodeNr] = NULL;
4154}
4155
4156/**
4157 * xmlXPathFreeNodeSet:
4158 * @obj: the xmlNodeSetPtr to free
4159 *
4160 * Free the NodeSet compound (not the actual nodes !).
4161 */
4162void
4163xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4164 if (obj == NULL) return;
4165 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004166 int i;
4167
William M. Brack08171912003-12-29 02:52:11 +00004168 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004169 for (i = 0;i < obj->nodeNr;i++)
4170 if ((obj->nodeTab[i] != NULL) &&
4171 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4172 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004173 xmlFree(obj->nodeTab);
4174 }
Owen Taylor3473f882001-02-23 17:55:21 +00004175 xmlFree(obj);
4176}
4177
4178/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004179 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004180 * @set: the node set to clear
Daniel Veillard45490ae2008-07-29 09:13:19 +00004181 *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004182 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4183 * are feed), but does *not* free the list itself. Sets the length of the
4184 * list to 0.
4185 */
4186static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004187xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4188{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004189 if ((set == NULL) || (set->nodeNr <= 0))
4190 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004191 else if (hasNsNodes) {
4192 int i;
4193 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004194
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004195 for (i = 0; i < set->nodeNr; i++) {
4196 node = set->nodeTab[i];
4197 if ((node != NULL) &&
4198 (node->type == XML_NAMESPACE_DECL))
4199 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004200 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004201 }
4202 set->nodeNr = 0;
4203}
4204
4205/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004206 * xmlXPathNodeSetClearFromPos:
4207 * @set: the node set to be cleared
4208 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004209 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004210 * Clears the list from temporary XPath objects (e.g. namespace nodes
4211 * are feed) starting with the entry at @pos, but does *not* free the list
4212 * itself. Sets the length of the list to @pos.
4213 */
4214static void
4215xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4216{
4217 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4218 return;
4219 else if ((hasNsNodes)) {
4220 int i;
4221 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004222
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004223 for (i = pos; i < set->nodeNr; i++) {
4224 node = set->nodeTab[i];
4225 if ((node != NULL) &&
4226 (node->type == XML_NAMESPACE_DECL))
4227 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004228 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004229 }
4230 set->nodeNr = pos;
4231}
4232
4233/**
Owen Taylor3473f882001-02-23 17:55:21 +00004234 * xmlXPathFreeValueTree:
4235 * @obj: the xmlNodeSetPtr to free
4236 *
4237 * Free the NodeSet compound and the actual tree, this is different
4238 * from xmlXPathFreeNodeSet()
4239 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004240static void
Owen Taylor3473f882001-02-23 17:55:21 +00004241xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4242 int i;
4243
4244 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004245
4246 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004247 for (i = 0;i < obj->nodeNr;i++) {
4248 if (obj->nodeTab[i] != NULL) {
4249 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4250 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4251 } else {
4252 xmlFreeNodeList(obj->nodeTab[i]);
4253 }
4254 }
4255 }
Owen Taylor3473f882001-02-23 17:55:21 +00004256 xmlFree(obj->nodeTab);
4257 }
Owen Taylor3473f882001-02-23 17:55:21 +00004258 xmlFree(obj);
4259}
4260
4261#if defined(DEBUG) || defined(DEBUG_STEP)
4262/**
4263 * xmlGenericErrorContextNodeSet:
4264 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004265 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004266 *
4267 * Quick display of a NodeSet
4268 */
4269void
4270xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4271 int i;
4272
4273 if (output == NULL) output = xmlGenericErrorContext;
4274 if (obj == NULL) {
4275 fprintf(output, "NodeSet == NULL !\n");
4276 return;
4277 }
4278 if (obj->nodeNr == 0) {
4279 fprintf(output, "NodeSet is empty\n");
4280 return;
4281 }
4282 if (obj->nodeTab == NULL) {
4283 fprintf(output, " nodeTab == NULL !\n");
4284 return;
4285 }
4286 for (i = 0; i < obj->nodeNr; i++) {
4287 if (obj->nodeTab[i] == NULL) {
4288 fprintf(output, " NULL !\n");
4289 return;
4290 }
4291 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4292 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4293 fprintf(output, " /");
4294 else if (obj->nodeTab[i]->name == NULL)
4295 fprintf(output, " noname!");
4296 else fprintf(output, " %s", obj->nodeTab[i]->name);
4297 }
4298 fprintf(output, "\n");
4299}
4300#endif
4301
4302/**
4303 * xmlXPathNewNodeSet:
4304 * @val: the NodePtr value
4305 *
4306 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4307 * it with the single Node @val
4308 *
4309 * Returns the newly created object.
4310 */
4311xmlXPathObjectPtr
4312xmlXPathNewNodeSet(xmlNodePtr val) {
4313 xmlXPathObjectPtr ret;
4314
4315 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4316 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004317 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004318 return(NULL);
4319 }
4320 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4321 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004322 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004323 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004324 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004325#ifdef XP_DEBUG_OBJ_USAGE
4326 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4327#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004328 return(ret);
4329}
4330
4331/**
4332 * xmlXPathNewValueTree:
4333 * @val: the NodePtr value
4334 *
4335 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4336 * it with the tree root @val
4337 *
4338 * Returns the newly created object.
4339 */
4340xmlXPathObjectPtr
4341xmlXPathNewValueTree(xmlNodePtr val) {
4342 xmlXPathObjectPtr ret;
4343
4344 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4345 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004346 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004347 return(NULL);
4348 }
4349 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4350 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004351 ret->boolval = 1;
4352 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004353 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004354#ifdef XP_DEBUG_OBJ_USAGE
4355 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4356#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004357 return(ret);
4358}
4359
4360/**
4361 * xmlXPathNewNodeSetList:
4362 * @val: an existing NodeSet
4363 *
4364 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4365 * it with the Nodeset @val
4366 *
4367 * Returns the newly created object.
4368 */
4369xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004370xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4371{
Owen Taylor3473f882001-02-23 17:55:21 +00004372 xmlXPathObjectPtr ret;
4373 int i;
4374
4375 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004376 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004377 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004378 ret = xmlXPathNewNodeSet(NULL);
4379 else {
4380 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004381 if (ret)
4382 for (i = 1; i < val->nodeNr; ++i)
4383 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004384 }
Owen Taylor3473f882001-02-23 17:55:21 +00004385
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004386 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004387}
4388
4389/**
4390 * xmlXPathWrapNodeSet:
4391 * @val: the NodePtr value
4392 *
4393 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4394 *
4395 * Returns the newly created object.
4396 */
4397xmlXPathObjectPtr
4398xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4399 xmlXPathObjectPtr ret;
4400
4401 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4402 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004403 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004404 return(NULL);
4405 }
4406 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4407 ret->type = XPATH_NODESET;
4408 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004409#ifdef XP_DEBUG_OBJ_USAGE
4410 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4411#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004412 return(ret);
4413}
4414
4415/**
4416 * xmlXPathFreeNodeSetList:
4417 * @obj: an existing NodeSetList object
4418 *
4419 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4420 * the list contrary to xmlXPathFreeObject().
4421 */
4422void
4423xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4424 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004425#ifdef XP_DEBUG_OBJ_USAGE
4426 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4427#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004428 xmlFree(obj);
4429}
4430
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004431/**
4432 * xmlXPathDifference:
4433 * @nodes1: a node-set
4434 * @nodes2: a node-set
4435 *
4436 * Implements the EXSLT - Sets difference() function:
4437 * node-set set:difference (node-set, node-set)
4438 *
4439 * Returns the difference between the two node sets, or nodes1 if
4440 * nodes2 is empty
4441 */
4442xmlNodeSetPtr
4443xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4444 xmlNodeSetPtr ret;
4445 int i, l1;
4446 xmlNodePtr cur;
4447
4448 if (xmlXPathNodeSetIsEmpty(nodes2))
4449 return(nodes1);
4450
4451 ret = xmlXPathNodeSetCreate(NULL);
4452 if (xmlXPathNodeSetIsEmpty(nodes1))
4453 return(ret);
4454
4455 l1 = xmlXPathNodeSetGetLength(nodes1);
4456
4457 for (i = 0; i < l1; i++) {
4458 cur = xmlXPathNodeSetItem(nodes1, i);
4459 if (!xmlXPathNodeSetContains(nodes2, cur))
4460 xmlXPathNodeSetAddUnique(ret, cur);
4461 }
4462 return(ret);
4463}
4464
4465/**
4466 * xmlXPathIntersection:
4467 * @nodes1: a node-set
4468 * @nodes2: a node-set
4469 *
4470 * Implements the EXSLT - Sets intersection() function:
4471 * node-set set:intersection (node-set, node-set)
4472 *
4473 * Returns a node set comprising the nodes that are within both the
4474 * node sets passed as arguments
4475 */
4476xmlNodeSetPtr
4477xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4478 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4479 int i, l1;
4480 xmlNodePtr cur;
4481
Daniel Veillardf88d8492008-04-01 08:00:31 +00004482 if (ret == NULL)
4483 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004484 if (xmlXPathNodeSetIsEmpty(nodes1))
4485 return(ret);
4486 if (xmlXPathNodeSetIsEmpty(nodes2))
4487 return(ret);
4488
4489 l1 = xmlXPathNodeSetGetLength(nodes1);
4490
4491 for (i = 0; i < l1; i++) {
4492 cur = xmlXPathNodeSetItem(nodes1, i);
4493 if (xmlXPathNodeSetContains(nodes2, cur))
4494 xmlXPathNodeSetAddUnique(ret, cur);
4495 }
4496 return(ret);
4497}
4498
4499/**
4500 * xmlXPathDistinctSorted:
4501 * @nodes: a node-set, sorted by document order
4502 *
4503 * Implements the EXSLT - Sets distinct() function:
4504 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004505 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004506 * Returns a subset of the nodes contained in @nodes, or @nodes if
4507 * it is empty
4508 */
4509xmlNodeSetPtr
4510xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4511 xmlNodeSetPtr ret;
4512 xmlHashTablePtr hash;
4513 int i, l;
4514 xmlChar * strval;
4515 xmlNodePtr cur;
4516
4517 if (xmlXPathNodeSetIsEmpty(nodes))
4518 return(nodes);
4519
4520 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004521 if (ret == NULL)
4522 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004523 l = xmlXPathNodeSetGetLength(nodes);
4524 hash = xmlHashCreate (l);
4525 for (i = 0; i < l; i++) {
4526 cur = xmlXPathNodeSetItem(nodes, i);
4527 strval = xmlXPathCastNodeToString(cur);
4528 if (xmlHashLookup(hash, strval) == NULL) {
4529 xmlHashAddEntry(hash, strval, strval);
4530 xmlXPathNodeSetAddUnique(ret, cur);
4531 } else {
4532 xmlFree(strval);
4533 }
4534 }
4535 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4536 return(ret);
4537}
4538
4539/**
4540 * xmlXPathDistinct:
4541 * @nodes: a node-set
4542 *
4543 * Implements the EXSLT - Sets distinct() function:
4544 * node-set set:distinct (node-set)
4545 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4546 * is called with the sorted node-set
4547 *
4548 * Returns a subset of the nodes contained in @nodes, or @nodes if
4549 * it is empty
4550 */
4551xmlNodeSetPtr
4552xmlXPathDistinct (xmlNodeSetPtr nodes) {
4553 if (xmlXPathNodeSetIsEmpty(nodes))
4554 return(nodes);
4555
4556 xmlXPathNodeSetSort(nodes);
4557 return(xmlXPathDistinctSorted(nodes));
4558}
4559
4560/**
4561 * xmlXPathHasSameNodes:
4562 * @nodes1: a node-set
4563 * @nodes2: a node-set
4564 *
4565 * Implements the EXSLT - Sets has-same-nodes function:
4566 * boolean set:has-same-node(node-set, node-set)
4567 *
4568 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4569 * otherwise
4570 */
4571int
4572xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4573 int i, l;
4574 xmlNodePtr cur;
4575
4576 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4577 xmlXPathNodeSetIsEmpty(nodes2))
4578 return(0);
4579
4580 l = xmlXPathNodeSetGetLength(nodes1);
4581 for (i = 0; i < l; i++) {
4582 cur = xmlXPathNodeSetItem(nodes1, i);
4583 if (xmlXPathNodeSetContains(nodes2, cur))
4584 return(1);
4585 }
4586 return(0);
4587}
4588
4589/**
4590 * xmlXPathNodeLeadingSorted:
4591 * @nodes: a node-set, sorted by document order
4592 * @node: a node
4593 *
4594 * Implements the EXSLT - Sets leading() function:
4595 * node-set set:leading (node-set, node-set)
4596 *
4597 * Returns the nodes in @nodes that precede @node in document order,
4598 * @nodes if @node is NULL or an empty node-set if @nodes
4599 * doesn't contain @node
4600 */
4601xmlNodeSetPtr
4602xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4603 int i, l;
4604 xmlNodePtr cur;
4605 xmlNodeSetPtr ret;
4606
4607 if (node == NULL)
4608 return(nodes);
4609
4610 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004611 if (ret == NULL)
4612 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004613 if (xmlXPathNodeSetIsEmpty(nodes) ||
4614 (!xmlXPathNodeSetContains(nodes, node)))
4615 return(ret);
4616
4617 l = xmlXPathNodeSetGetLength(nodes);
4618 for (i = 0; i < l; i++) {
4619 cur = xmlXPathNodeSetItem(nodes, i);
4620 if (cur == node)
4621 break;
4622 xmlXPathNodeSetAddUnique(ret, cur);
4623 }
4624 return(ret);
4625}
4626
4627/**
4628 * xmlXPathNodeLeading:
4629 * @nodes: a node-set
4630 * @node: a node
4631 *
4632 * Implements the EXSLT - Sets leading() function:
4633 * node-set set:leading (node-set, node-set)
4634 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4635 * is called.
4636 *
4637 * Returns the nodes in @nodes that precede @node in document order,
4638 * @nodes if @node is NULL or an empty node-set if @nodes
4639 * doesn't contain @node
4640 */
4641xmlNodeSetPtr
4642xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4643 xmlXPathNodeSetSort(nodes);
4644 return(xmlXPathNodeLeadingSorted(nodes, node));
4645}
4646
4647/**
4648 * xmlXPathLeadingSorted:
4649 * @nodes1: a node-set, sorted by document order
4650 * @nodes2: a node-set, sorted by document order
4651 *
4652 * Implements the EXSLT - Sets leading() function:
4653 * node-set set:leading (node-set, node-set)
4654 *
4655 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4656 * in document order, @nodes1 if @nodes2 is NULL or empty or
4657 * an empty node-set if @nodes1 doesn't contain @nodes2
4658 */
4659xmlNodeSetPtr
4660xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4661 if (xmlXPathNodeSetIsEmpty(nodes2))
4662 return(nodes1);
4663 return(xmlXPathNodeLeadingSorted(nodes1,
4664 xmlXPathNodeSetItem(nodes2, 1)));
4665}
4666
4667/**
4668 * xmlXPathLeading:
4669 * @nodes1: a node-set
4670 * @nodes2: a node-set
4671 *
4672 * Implements the EXSLT - Sets leading() function:
4673 * node-set set:leading (node-set, node-set)
4674 * @nodes1 and @nodes2 are sorted by document order, then
4675 * #exslSetsLeadingSorted is called.
4676 *
4677 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4678 * in document order, @nodes1 if @nodes2 is NULL or empty or
4679 * an empty node-set if @nodes1 doesn't contain @nodes2
4680 */
4681xmlNodeSetPtr
4682xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4683 if (xmlXPathNodeSetIsEmpty(nodes2))
4684 return(nodes1);
4685 if (xmlXPathNodeSetIsEmpty(nodes1))
4686 return(xmlXPathNodeSetCreate(NULL));
4687 xmlXPathNodeSetSort(nodes1);
4688 xmlXPathNodeSetSort(nodes2);
4689 return(xmlXPathNodeLeadingSorted(nodes1,
4690 xmlXPathNodeSetItem(nodes2, 1)));
4691}
4692
4693/**
4694 * xmlXPathNodeTrailingSorted:
4695 * @nodes: a node-set, sorted by document order
4696 * @node: a node
4697 *
4698 * Implements the EXSLT - Sets trailing() function:
4699 * node-set set:trailing (node-set, node-set)
4700 *
4701 * Returns the nodes in @nodes that follow @node in document order,
4702 * @nodes if @node is NULL or an empty node-set if @nodes
4703 * doesn't contain @node
4704 */
4705xmlNodeSetPtr
4706xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4707 int i, l;
4708 xmlNodePtr cur;
4709 xmlNodeSetPtr ret;
4710
4711 if (node == NULL)
4712 return(nodes);
4713
4714 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004715 if (ret == NULL)
4716 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004717 if (xmlXPathNodeSetIsEmpty(nodes) ||
4718 (!xmlXPathNodeSetContains(nodes, node)))
4719 return(ret);
4720
4721 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004722 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004723 cur = xmlXPathNodeSetItem(nodes, i);
4724 if (cur == node)
4725 break;
4726 xmlXPathNodeSetAddUnique(ret, cur);
4727 }
William M. Brack97ac8192007-06-06 17:19:24 +00004728 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004729 return(ret);
4730}
4731
4732/**
4733 * xmlXPathNodeTrailing:
4734 * @nodes: a node-set
4735 * @node: a node
4736 *
4737 * Implements the EXSLT - Sets trailing() function:
4738 * node-set set:trailing (node-set, node-set)
4739 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4740 * is called.
4741 *
4742 * Returns the nodes in @nodes that follow @node in document order,
4743 * @nodes if @node is NULL or an empty node-set if @nodes
4744 * doesn't contain @node
4745 */
4746xmlNodeSetPtr
4747xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4748 xmlXPathNodeSetSort(nodes);
4749 return(xmlXPathNodeTrailingSorted(nodes, node));
4750}
4751
4752/**
4753 * xmlXPathTrailingSorted:
4754 * @nodes1: a node-set, sorted by document order
4755 * @nodes2: a node-set, sorted by document order
4756 *
4757 * Implements the EXSLT - Sets trailing() function:
4758 * node-set set:trailing (node-set, node-set)
4759 *
4760 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4761 * in document order, @nodes1 if @nodes2 is NULL or empty or
4762 * an empty node-set if @nodes1 doesn't contain @nodes2
4763 */
4764xmlNodeSetPtr
4765xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4766 if (xmlXPathNodeSetIsEmpty(nodes2))
4767 return(nodes1);
4768 return(xmlXPathNodeTrailingSorted(nodes1,
4769 xmlXPathNodeSetItem(nodes2, 0)));
4770}
4771
4772/**
4773 * xmlXPathTrailing:
4774 * @nodes1: a node-set
4775 * @nodes2: a node-set
4776 *
4777 * Implements the EXSLT - Sets trailing() function:
4778 * node-set set:trailing (node-set, node-set)
4779 * @nodes1 and @nodes2 are sorted by document order, then
4780 * #xmlXPathTrailingSorted is called.
4781 *
4782 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4783 * in document order, @nodes1 if @nodes2 is NULL or empty or
4784 * an empty node-set if @nodes1 doesn't contain @nodes2
4785 */
4786xmlNodeSetPtr
4787xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4788 if (xmlXPathNodeSetIsEmpty(nodes2))
4789 return(nodes1);
4790 if (xmlXPathNodeSetIsEmpty(nodes1))
4791 return(xmlXPathNodeSetCreate(NULL));
4792 xmlXPathNodeSetSort(nodes1);
4793 xmlXPathNodeSetSort(nodes2);
4794 return(xmlXPathNodeTrailingSorted(nodes1,
4795 xmlXPathNodeSetItem(nodes2, 0)));
4796}
4797
Owen Taylor3473f882001-02-23 17:55:21 +00004798/************************************************************************
4799 * *
4800 * Routines to handle extra functions *
4801 * *
4802 ************************************************************************/
4803
4804/**
4805 * xmlXPathRegisterFunc:
4806 * @ctxt: the XPath context
4807 * @name: the function name
4808 * @f: the function implementation or NULL
4809 *
4810 * Register a new function. If @f is NULL it unregisters the function
4811 *
4812 * Returns 0 in case of success, -1 in case of error
4813 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004814int
Owen Taylor3473f882001-02-23 17:55:21 +00004815xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4816 xmlXPathFunction f) {
4817 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4818}
4819
4820/**
4821 * xmlXPathRegisterFuncNS:
4822 * @ctxt: the XPath context
4823 * @name: the function name
4824 * @ns_uri: the function namespace URI
4825 * @f: the function implementation or NULL
4826 *
4827 * Register a new function. If @f is NULL it unregisters the function
4828 *
4829 * Returns 0 in case of success, -1 in case of error
4830 */
4831int
4832xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4833 const xmlChar *ns_uri, xmlXPathFunction f) {
4834 if (ctxt == NULL)
4835 return(-1);
4836 if (name == NULL)
4837 return(-1);
4838
4839 if (ctxt->funcHash == NULL)
4840 ctxt->funcHash = xmlHashCreate(0);
4841 if (ctxt->funcHash == NULL)
4842 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004843 if (f == NULL)
4844 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004845 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004846}
4847
4848/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004849 * xmlXPathRegisterFuncLookup:
4850 * @ctxt: the XPath context
4851 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004852 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004853 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004854 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004855 */
4856void
4857xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4858 xmlXPathFuncLookupFunc f,
4859 void *funcCtxt) {
4860 if (ctxt == NULL)
4861 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004862 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004863 ctxt->funcLookupData = funcCtxt;
4864}
4865
4866/**
Owen Taylor3473f882001-02-23 17:55:21 +00004867 * xmlXPathFunctionLookup:
4868 * @ctxt: the XPath context
4869 * @name: the function name
4870 *
4871 * Search in the Function array of the context for the given
4872 * function.
4873 *
4874 * Returns the xmlXPathFunction or NULL if not found
4875 */
4876xmlXPathFunction
4877xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004878 if (ctxt == NULL)
4879 return (NULL);
4880
4881 if (ctxt->funcLookupFunc != NULL) {
4882 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004883 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004884
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004885 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004886 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004887 if (ret != NULL)
4888 return(ret);
4889 }
Owen Taylor3473f882001-02-23 17:55:21 +00004890 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4891}
4892
4893/**
4894 * xmlXPathFunctionLookupNS:
4895 * @ctxt: the XPath context
4896 * @name: the function name
4897 * @ns_uri: the function namespace URI
4898 *
4899 * Search in the Function array of the context for the given
4900 * function.
4901 *
4902 * Returns the xmlXPathFunction or NULL if not found
4903 */
4904xmlXPathFunction
4905xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4906 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004907 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004908
Owen Taylor3473f882001-02-23 17:55:21 +00004909 if (ctxt == NULL)
4910 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004911 if (name == NULL)
4912 return(NULL);
4913
Thomas Broyerba4ad322001-07-26 16:55:21 +00004914 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004915 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004916
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004917 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004918 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004919 if (ret != NULL)
4920 return(ret);
4921 }
4922
4923 if (ctxt->funcHash == NULL)
4924 return(NULL);
4925
William M. Brackad0e67c2004-12-01 14:35:10 +00004926 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4927 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004928}
4929
4930/**
4931 * xmlXPathRegisteredFuncsCleanup:
4932 * @ctxt: the XPath context
4933 *
4934 * Cleanup the XPath context data associated to registered functions
4935 */
4936void
4937xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4938 if (ctxt == NULL)
4939 return;
4940
4941 xmlHashFree(ctxt->funcHash, NULL);
4942 ctxt->funcHash = NULL;
4943}
4944
4945/************************************************************************
4946 * *
William M. Brack08171912003-12-29 02:52:11 +00004947 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004948 * *
4949 ************************************************************************/
4950
4951/**
4952 * xmlXPathRegisterVariable:
4953 * @ctxt: the XPath context
4954 * @name: the variable name
4955 * @value: the variable value or NULL
4956 *
4957 * Register a new variable value. If @value is NULL it unregisters
4958 * the variable
4959 *
4960 * Returns 0 in case of success, -1 in case of error
4961 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004962int
Owen Taylor3473f882001-02-23 17:55:21 +00004963xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4964 xmlXPathObjectPtr value) {
4965 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4966}
4967
4968/**
4969 * xmlXPathRegisterVariableNS:
4970 * @ctxt: the XPath context
4971 * @name: the variable name
4972 * @ns_uri: the variable namespace URI
4973 * @value: the variable value or NULL
4974 *
4975 * Register a new variable value. If @value is NULL it unregisters
4976 * the variable
4977 *
4978 * Returns 0 in case of success, -1 in case of error
4979 */
4980int
4981xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4982 const xmlChar *ns_uri,
4983 xmlXPathObjectPtr value) {
4984 if (ctxt == NULL)
4985 return(-1);
4986 if (name == NULL)
4987 return(-1);
4988
4989 if (ctxt->varHash == NULL)
4990 ctxt->varHash = xmlHashCreate(0);
4991 if (ctxt->varHash == NULL)
4992 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004993 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004994 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00004995 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004996 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4997 (void *) value,
4998 (xmlHashDeallocator)xmlXPathFreeObject));
4999}
5000
5001/**
5002 * xmlXPathRegisterVariableLookup:
5003 * @ctxt: the XPath context
5004 * @f: the lookup function
5005 * @data: the lookup data
5006 *
5007 * register an external mechanism to do variable lookup
5008 */
5009void
5010xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5011 xmlXPathVariableLookupFunc f, void *data) {
5012 if (ctxt == NULL)
5013 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00005014 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00005015 ctxt->varLookupData = data;
5016}
5017
5018/**
5019 * xmlXPathVariableLookup:
5020 * @ctxt: the XPath context
5021 * @name: the variable name
5022 *
5023 * Search in the Variable array of the context for the given
5024 * variable value.
5025 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005026 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005027 */
5028xmlXPathObjectPtr
5029xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5030 if (ctxt == NULL)
5031 return(NULL);
5032
5033 if (ctxt->varLookupFunc != NULL) {
5034 xmlXPathObjectPtr ret;
5035
5036 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5037 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00005038 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005039 }
5040 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5041}
5042
5043/**
5044 * xmlXPathVariableLookupNS:
5045 * @ctxt: the XPath context
5046 * @name: the variable name
5047 * @ns_uri: the variable namespace URI
5048 *
5049 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005050 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005051 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005052 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005053 */
5054xmlXPathObjectPtr
5055xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5056 const xmlChar *ns_uri) {
5057 if (ctxt == NULL)
5058 return(NULL);
5059
5060 if (ctxt->varLookupFunc != NULL) {
5061 xmlXPathObjectPtr ret;
5062
5063 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5064 (ctxt->varLookupData, name, ns_uri);
5065 if (ret != NULL) return(ret);
5066 }
5067
5068 if (ctxt->varHash == NULL)
5069 return(NULL);
5070 if (name == NULL)
5071 return(NULL);
5072
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005073 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005074 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005075}
5076
5077/**
5078 * xmlXPathRegisteredVariablesCleanup:
5079 * @ctxt: the XPath context
5080 *
5081 * Cleanup the XPath context data associated to registered variables
5082 */
5083void
5084xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5085 if (ctxt == NULL)
5086 return;
5087
Daniel Veillard76d66f42001-05-16 21:05:17 +00005088 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005089 ctxt->varHash = NULL;
5090}
5091
5092/**
5093 * xmlXPathRegisterNs:
5094 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005095 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005096 * @ns_uri: the namespace name
5097 *
5098 * Register a new namespace. If @ns_uri is NULL it unregisters
5099 * the namespace
5100 *
5101 * Returns 0 in case of success, -1 in case of error
5102 */
5103int
5104xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5105 const xmlChar *ns_uri) {
5106 if (ctxt == NULL)
5107 return(-1);
5108 if (prefix == NULL)
5109 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005110 if (prefix[0] == 0)
5111 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005112
5113 if (ctxt->nsHash == NULL)
5114 ctxt->nsHash = xmlHashCreate(10);
5115 if (ctxt->nsHash == NULL)
5116 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005117 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005118 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005119 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005120 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005121 (xmlHashDeallocator)xmlFree));
5122}
5123
5124/**
5125 * xmlXPathNsLookup:
5126 * @ctxt: the XPath context
5127 * @prefix: the namespace prefix value
5128 *
5129 * Search in the namespace declaration array of the context for the given
5130 * namespace name associated to the given prefix
5131 *
5132 * Returns the value or NULL if not found
5133 */
5134const xmlChar *
5135xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5136 if (ctxt == NULL)
5137 return(NULL);
5138 if (prefix == NULL)
5139 return(NULL);
5140
5141#ifdef XML_XML_NAMESPACE
5142 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5143 return(XML_XML_NAMESPACE);
5144#endif
5145
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005146 if (ctxt->namespaces != NULL) {
5147 int i;
5148
5149 for (i = 0;i < ctxt->nsNr;i++) {
5150 if ((ctxt->namespaces[i] != NULL) &&
5151 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5152 return(ctxt->namespaces[i]->href);
5153 }
5154 }
Owen Taylor3473f882001-02-23 17:55:21 +00005155
5156 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5157}
5158
5159/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005160 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005161 * @ctxt: the XPath context
5162 *
5163 * Cleanup the XPath context data associated to registered variables
5164 */
5165void
5166xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5167 if (ctxt == NULL)
5168 return;
5169
Daniel Veillard42766c02002-08-22 20:52:17 +00005170 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005171 ctxt->nsHash = NULL;
5172}
5173
5174/************************************************************************
5175 * *
5176 * Routines to handle Values *
5177 * *
5178 ************************************************************************/
5179
William M. Brack08171912003-12-29 02:52:11 +00005180/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005181
5182/**
5183 * xmlXPathNewFloat:
5184 * @val: the double value
5185 *
5186 * Create a new xmlXPathObjectPtr of type double and of value @val
5187 *
5188 * Returns the newly created object.
5189 */
5190xmlXPathObjectPtr
5191xmlXPathNewFloat(double val) {
5192 xmlXPathObjectPtr ret;
5193
5194 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5195 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005196 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005197 return(NULL);
5198 }
5199 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5200 ret->type = XPATH_NUMBER;
5201 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005202#ifdef XP_DEBUG_OBJ_USAGE
5203 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5204#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005205 return(ret);
5206}
5207
5208/**
5209 * xmlXPathNewBoolean:
5210 * @val: the boolean value
5211 *
5212 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5213 *
5214 * Returns the newly created object.
5215 */
5216xmlXPathObjectPtr
5217xmlXPathNewBoolean(int val) {
5218 xmlXPathObjectPtr ret;
5219
5220 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5221 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005222 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005223 return(NULL);
5224 }
5225 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5226 ret->type = XPATH_BOOLEAN;
5227 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005228#ifdef XP_DEBUG_OBJ_USAGE
5229 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5230#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005231 return(ret);
5232}
5233
5234/**
5235 * xmlXPathNewString:
5236 * @val: the xmlChar * value
5237 *
5238 * Create a new xmlXPathObjectPtr of type string and of value @val
5239 *
5240 * Returns the newly created object.
5241 */
5242xmlXPathObjectPtr
5243xmlXPathNewString(const xmlChar *val) {
5244 xmlXPathObjectPtr ret;
5245
5246 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005248 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005249 return(NULL);
5250 }
5251 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5252 ret->type = XPATH_STRING;
5253 if (val != NULL)
5254 ret->stringval = xmlStrdup(val);
5255 else
5256 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005257#ifdef XP_DEBUG_OBJ_USAGE
5258 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5259#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005260 return(ret);
5261}
5262
5263/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005264 * xmlXPathWrapString:
5265 * @val: the xmlChar * value
5266 *
5267 * Wraps the @val string into an XPath object.
5268 *
5269 * Returns the newly created object.
5270 */
5271xmlXPathObjectPtr
5272xmlXPathWrapString (xmlChar *val) {
5273 xmlXPathObjectPtr ret;
5274
5275 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5276 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005277 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005278 return(NULL);
5279 }
5280 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5281 ret->type = XPATH_STRING;
5282 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005283#ifdef XP_DEBUG_OBJ_USAGE
5284 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5285#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005286 return(ret);
5287}
5288
5289/**
Owen Taylor3473f882001-02-23 17:55:21 +00005290 * xmlXPathNewCString:
5291 * @val: the char * value
5292 *
5293 * Create a new xmlXPathObjectPtr of type string and of value @val
5294 *
5295 * Returns the newly created object.
5296 */
5297xmlXPathObjectPtr
5298xmlXPathNewCString(const char *val) {
5299 xmlXPathObjectPtr ret;
5300
5301 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5302 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005303 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005304 return(NULL);
5305 }
5306 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5307 ret->type = XPATH_STRING;
5308 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005309#ifdef XP_DEBUG_OBJ_USAGE
5310 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5311#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005312 return(ret);
5313}
5314
5315/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005316 * xmlXPathWrapCString:
5317 * @val: the char * value
5318 *
5319 * Wraps a string into an XPath object.
5320 *
5321 * Returns the newly created object.
5322 */
5323xmlXPathObjectPtr
5324xmlXPathWrapCString (char * val) {
5325 return(xmlXPathWrapString((xmlChar *)(val)));
5326}
5327
5328/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005329 * xmlXPathWrapExternal:
5330 * @val: the user data
5331 *
5332 * Wraps the @val data into an XPath object.
5333 *
5334 * Returns the newly created object.
5335 */
5336xmlXPathObjectPtr
5337xmlXPathWrapExternal (void *val) {
5338 xmlXPathObjectPtr ret;
5339
5340 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5341 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005342 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005343 return(NULL);
5344 }
5345 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5346 ret->type = XPATH_USERS;
5347 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005348#ifdef XP_DEBUG_OBJ_USAGE
5349 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5350#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005351 return(ret);
5352}
5353
5354/**
Owen Taylor3473f882001-02-23 17:55:21 +00005355 * xmlXPathObjectCopy:
5356 * @val: the original object
5357 *
5358 * allocate a new copy of a given object
5359 *
5360 * Returns the newly created object.
5361 */
5362xmlXPathObjectPtr
5363xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5364 xmlXPathObjectPtr ret;
5365
5366 if (val == NULL)
5367 return(NULL);
5368
5369 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5370 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005371 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005372 return(NULL);
5373 }
5374 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005375#ifdef XP_DEBUG_OBJ_USAGE
5376 xmlXPathDebugObjUsageRequested(NULL, val->type);
5377#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005378 switch (val->type) {
5379 case XPATH_BOOLEAN:
5380 case XPATH_NUMBER:
5381 case XPATH_POINT:
5382 case XPATH_RANGE:
5383 break;
5384 case XPATH_STRING:
5385 ret->stringval = xmlStrdup(val->stringval);
5386 break;
5387 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005388#if 0
5389/*
5390 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5391 this previous handling is no longer correct, and can cause some serious
5392 problems (ref. bug 145547)
5393*/
Owen Taylor3473f882001-02-23 17:55:21 +00005394 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005395 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005396 xmlNodePtr cur, tmp;
5397 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005398
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005399 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005400 top = xmlNewDoc(NULL);
5401 top->name = (char *)
5402 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005403 ret->user = top;
5404 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005405 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005406 cur = val->nodesetval->nodeTab[0]->children;
5407 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005408 tmp = xmlDocCopyNode(cur, top, 1);
5409 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005410 cur = cur->next;
5411 }
5412 }
William M. Bracke9449c52004-07-11 14:41:20 +00005413
Daniel Veillard9adc0462003-03-24 18:39:54 +00005414 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005415 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005416 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005417 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005418 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005419#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005420 case XPATH_NODESET:
5421 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005422 /* Do not deallocate the copied tree value */
5423 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005424 break;
5425 case XPATH_LOCATIONSET:
5426#ifdef LIBXML_XPTR_ENABLED
5427 {
5428 xmlLocationSetPtr loc = val->user;
5429 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5430 break;
5431 }
5432#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005433 case XPATH_USERS:
5434 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005435 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005436 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005437 xmlGenericError(xmlGenericErrorContext,
5438 "xmlXPathObjectCopy: unsupported type %d\n",
5439 val->type);
5440 break;
5441 }
5442 return(ret);
5443}
5444
5445/**
5446 * xmlXPathFreeObject:
5447 * @obj: the object to free
5448 *
5449 * Free up an xmlXPathObjectPtr object.
5450 */
5451void
5452xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5453 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005454 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005455 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005456#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005457 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005458 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005459 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005460 } else
5461#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005462 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005463 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005464 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005465 } else {
5466 if (obj->nodesetval != NULL)
5467 xmlXPathFreeNodeSet(obj->nodesetval);
5468 }
Owen Taylor3473f882001-02-23 17:55:21 +00005469#ifdef LIBXML_XPTR_ENABLED
5470 } else if (obj->type == XPATH_LOCATIONSET) {
5471 if (obj->user != NULL)
5472 xmlXPtrFreeLocationSet(obj->user);
5473#endif
5474 } else if (obj->type == XPATH_STRING) {
5475 if (obj->stringval != NULL)
5476 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005477 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005478#ifdef XP_DEBUG_OBJ_USAGE
5479 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5480#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005481 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005482}
Owen Taylor3473f882001-02-23 17:55:21 +00005483
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005484/**
5485 * xmlXPathReleaseObject:
5486 * @obj: the xmlXPathObjectPtr to free or to cache
5487 *
5488 * Depending on the state of the cache this frees the given
5489 * XPath object or stores it in the cache.
5490 */
5491static void
5492xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5493{
5494#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5495 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5496 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5497
5498#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5499
5500 if (obj == NULL)
5501 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005502 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005503 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005504 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005505 xmlXPathContextCachePtr cache =
5506 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005507
5508 switch (obj->type) {
5509 case XPATH_NODESET:
5510 case XPATH_XSLT_TREE:
5511 if (obj->nodesetval != NULL) {
5512 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005513 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005514 * It looks like the @boolval is used for
5515 * evaluation if this an XSLT Result Tree Fragment.
5516 * TODO: Check if this assumption is correct.
5517 */
5518 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5519 xmlXPathFreeValueTree(obj->nodesetval);
5520 obj->nodesetval = NULL;
5521 } else if ((obj->nodesetval->nodeMax <= 40) &&
5522 (XP_CACHE_WANTS(cache->nodesetObjs,
5523 cache->maxNodeset)))
5524 {
5525 XP_CACHE_ADD(cache->nodesetObjs, obj);
5526 goto obj_cached;
5527 } else {
5528 xmlXPathFreeNodeSet(obj->nodesetval);
5529 obj->nodesetval = NULL;
5530 }
5531 }
5532 break;
5533 case XPATH_STRING:
5534 if (obj->stringval != NULL)
5535 xmlFree(obj->stringval);
5536
5537 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5538 XP_CACHE_ADD(cache->stringObjs, obj);
5539 goto obj_cached;
5540 }
5541 break;
5542 case XPATH_BOOLEAN:
5543 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5544 XP_CACHE_ADD(cache->booleanObjs, obj);
5545 goto obj_cached;
5546 }
5547 break;
5548 case XPATH_NUMBER:
5549 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5550 XP_CACHE_ADD(cache->numberObjs, obj);
5551 goto obj_cached;
5552 }
5553 break;
5554#ifdef LIBXML_XPTR_ENABLED
5555 case XPATH_LOCATIONSET:
5556 if (obj->user != NULL) {
5557 xmlXPtrFreeLocationSet(obj->user);
5558 }
5559 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005560#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005561 default:
5562 goto free_obj;
5563 }
5564
5565 /*
5566 * Fallback to adding to the misc-objects slot.
5567 */
5568 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5569 XP_CACHE_ADD(cache->miscObjs, obj);
5570 } else
5571 goto free_obj;
5572
5573obj_cached:
5574
5575#ifdef XP_DEBUG_OBJ_USAGE
5576 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5577#endif
5578
5579 if (obj->nodesetval != NULL) {
5580 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005581
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005582 /*
5583 * TODO: Due to those nasty ns-nodes, we need to traverse
5584 * the list and free the ns-nodes.
5585 * URGENT TODO: Check if it's actually slowing things down.
5586 * Maybe we shouldn't try to preserve the list.
5587 */
5588 if (tmpset->nodeNr > 1) {
5589 int i;
5590 xmlNodePtr node;
5591
5592 for (i = 0; i < tmpset->nodeNr; i++) {
5593 node = tmpset->nodeTab[i];
5594 if ((node != NULL) &&
5595 (node->type == XML_NAMESPACE_DECL))
5596 {
5597 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5598 }
5599 }
5600 } else if (tmpset->nodeNr == 1) {
5601 if ((tmpset->nodeTab[0] != NULL) &&
5602 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5603 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005604 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005605 tmpset->nodeNr = 0;
5606 memset(obj, 0, sizeof(xmlXPathObject));
5607 obj->nodesetval = tmpset;
5608 } else
5609 memset(obj, 0, sizeof(xmlXPathObject));
5610
5611 return;
5612
5613free_obj:
5614 /*
5615 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005616 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005617 if (obj->nodesetval != NULL)
5618 xmlXPathFreeNodeSet(obj->nodesetval);
5619#ifdef XP_DEBUG_OBJ_USAGE
5620 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5621#endif
5622 xmlFree(obj);
5623 }
5624 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005625}
5626
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005627
5628/************************************************************************
5629 * *
5630 * Type Casting Routines *
5631 * *
5632 ************************************************************************/
5633
5634/**
5635 * xmlXPathCastBooleanToString:
5636 * @val: a boolean
5637 *
5638 * Converts a boolean to its string value.
5639 *
5640 * Returns a newly allocated string.
5641 */
5642xmlChar *
5643xmlXPathCastBooleanToString (int val) {
5644 xmlChar *ret;
5645 if (val)
5646 ret = xmlStrdup((const xmlChar *) "true");
5647 else
5648 ret = xmlStrdup((const xmlChar *) "false");
5649 return(ret);
5650}
5651
5652/**
5653 * xmlXPathCastNumberToString:
5654 * @val: a number
5655 *
5656 * Converts a number to its string value.
5657 *
5658 * Returns a newly allocated string.
5659 */
5660xmlChar *
5661xmlXPathCastNumberToString (double val) {
5662 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005663 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005664 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005665 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005666 break;
5667 case -1:
5668 ret = xmlStrdup((const xmlChar *) "-Infinity");
5669 break;
5670 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005671 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005672 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005673 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5674 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005675 } else {
5676 /* could be improved */
5677 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005678 xmlXPathFormatNumber(val, buf, 99);
5679 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005680 ret = xmlStrdup((const xmlChar *) buf);
5681 }
5682 }
5683 return(ret);
5684}
5685
5686/**
5687 * xmlXPathCastNodeToString:
5688 * @node: a node
5689 *
5690 * Converts a node to its string value.
5691 *
5692 * Returns a newly allocated string.
5693 */
5694xmlChar *
5695xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005696xmlChar *ret;
5697 if ((ret = xmlNodeGetContent(node)) == NULL)
5698 ret = xmlStrdup((const xmlChar *) "");
5699 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005700}
5701
5702/**
5703 * xmlXPathCastNodeSetToString:
5704 * @ns: a node-set
5705 *
5706 * Converts a node-set to its string value.
5707 *
5708 * Returns a newly allocated string.
5709 */
5710xmlChar *
5711xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5712 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5713 return(xmlStrdup((const xmlChar *) ""));
5714
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005715 if (ns->nodeNr > 1)
5716 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005717 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5718}
5719
5720/**
5721 * xmlXPathCastToString:
5722 * @val: an XPath object
5723 *
5724 * Converts an existing object to its string() equivalent
5725 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005726 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005727 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005728 */
5729xmlChar *
5730xmlXPathCastToString(xmlXPathObjectPtr val) {
5731 xmlChar *ret = NULL;
5732
5733 if (val == NULL)
5734 return(xmlStrdup((const xmlChar *) ""));
5735 switch (val->type) {
5736 case XPATH_UNDEFINED:
5737#ifdef DEBUG_EXPR
5738 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5739#endif
5740 ret = xmlStrdup((const xmlChar *) "");
5741 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005742 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005743 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005744 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5745 break;
5746 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005747 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005748 case XPATH_BOOLEAN:
5749 ret = xmlXPathCastBooleanToString(val->boolval);
5750 break;
5751 case XPATH_NUMBER: {
5752 ret = xmlXPathCastNumberToString(val->floatval);
5753 break;
5754 }
5755 case XPATH_USERS:
5756 case XPATH_POINT:
5757 case XPATH_RANGE:
5758 case XPATH_LOCATIONSET:
5759 TODO
5760 ret = xmlStrdup((const xmlChar *) "");
5761 break;
5762 }
5763 return(ret);
5764}
5765
5766/**
5767 * xmlXPathConvertString:
5768 * @val: an XPath object
5769 *
5770 * Converts an existing object to its string() equivalent
5771 *
5772 * Returns the new object, the old one is freed (or the operation
5773 * is done directly on @val)
5774 */
5775xmlXPathObjectPtr
5776xmlXPathConvertString(xmlXPathObjectPtr val) {
5777 xmlChar *res = NULL;
5778
5779 if (val == NULL)
5780 return(xmlXPathNewCString(""));
5781
5782 switch (val->type) {
5783 case XPATH_UNDEFINED:
5784#ifdef DEBUG_EXPR
5785 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5786#endif
5787 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005788 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005789 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005790 res = xmlXPathCastNodeSetToString(val->nodesetval);
5791 break;
5792 case XPATH_STRING:
5793 return(val);
5794 case XPATH_BOOLEAN:
5795 res = xmlXPathCastBooleanToString(val->boolval);
5796 break;
5797 case XPATH_NUMBER:
5798 res = xmlXPathCastNumberToString(val->floatval);
5799 break;
5800 case XPATH_USERS:
5801 case XPATH_POINT:
5802 case XPATH_RANGE:
5803 case XPATH_LOCATIONSET:
5804 TODO;
5805 break;
5806 }
5807 xmlXPathFreeObject(val);
5808 if (res == NULL)
5809 return(xmlXPathNewCString(""));
5810 return(xmlXPathWrapString(res));
5811}
5812
5813/**
5814 * xmlXPathCastBooleanToNumber:
5815 * @val: a boolean
5816 *
5817 * Converts a boolean to its number value
5818 *
5819 * Returns the number value
5820 */
5821double
5822xmlXPathCastBooleanToNumber(int val) {
5823 if (val)
5824 return(1.0);
5825 return(0.0);
5826}
5827
5828/**
5829 * xmlXPathCastStringToNumber:
5830 * @val: a string
5831 *
5832 * Converts a string to its number value
5833 *
5834 * Returns the number value
5835 */
5836double
5837xmlXPathCastStringToNumber(const xmlChar * val) {
5838 return(xmlXPathStringEvalNumber(val));
5839}
5840
5841/**
5842 * xmlXPathCastNodeToNumber:
5843 * @node: a node
5844 *
5845 * Converts a node to its number value
5846 *
5847 * Returns the number value
5848 */
5849double
5850xmlXPathCastNodeToNumber (xmlNodePtr node) {
5851 xmlChar *strval;
5852 double ret;
5853
5854 if (node == NULL)
5855 return(xmlXPathNAN);
5856 strval = xmlXPathCastNodeToString(node);
5857 if (strval == NULL)
5858 return(xmlXPathNAN);
5859 ret = xmlXPathCastStringToNumber(strval);
5860 xmlFree(strval);
5861
5862 return(ret);
5863}
5864
5865/**
5866 * xmlXPathCastNodeSetToNumber:
5867 * @ns: a node-set
5868 *
5869 * Converts a node-set to its number value
5870 *
5871 * Returns the number value
5872 */
5873double
5874xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5875 xmlChar *str;
5876 double ret;
5877
5878 if (ns == NULL)
5879 return(xmlXPathNAN);
5880 str = xmlXPathCastNodeSetToString(ns);
5881 ret = xmlXPathCastStringToNumber(str);
5882 xmlFree(str);
5883 return(ret);
5884}
5885
5886/**
5887 * xmlXPathCastToNumber:
5888 * @val: an XPath object
5889 *
5890 * Converts an XPath object to its number value
5891 *
5892 * Returns the number value
5893 */
5894double
5895xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5896 double ret = 0.0;
5897
5898 if (val == NULL)
5899 return(xmlXPathNAN);
5900 switch (val->type) {
5901 case XPATH_UNDEFINED:
5902#ifdef DEGUB_EXPR
5903 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5904#endif
5905 ret = xmlXPathNAN;
5906 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005907 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005908 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005909 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5910 break;
5911 case XPATH_STRING:
5912 ret = xmlXPathCastStringToNumber(val->stringval);
5913 break;
5914 case XPATH_NUMBER:
5915 ret = val->floatval;
5916 break;
5917 case XPATH_BOOLEAN:
5918 ret = xmlXPathCastBooleanToNumber(val->boolval);
5919 break;
5920 case XPATH_USERS:
5921 case XPATH_POINT:
5922 case XPATH_RANGE:
5923 case XPATH_LOCATIONSET:
5924 TODO;
5925 ret = xmlXPathNAN;
5926 break;
5927 }
5928 return(ret);
5929}
5930
5931/**
5932 * xmlXPathConvertNumber:
5933 * @val: an XPath object
5934 *
5935 * Converts an existing object to its number() equivalent
5936 *
5937 * Returns the new object, the old one is freed (or the operation
5938 * is done directly on @val)
5939 */
5940xmlXPathObjectPtr
5941xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5942 xmlXPathObjectPtr ret;
5943
5944 if (val == NULL)
5945 return(xmlXPathNewFloat(0.0));
5946 if (val->type == XPATH_NUMBER)
5947 return(val);
5948 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5949 xmlXPathFreeObject(val);
5950 return(ret);
5951}
5952
5953/**
5954 * xmlXPathCastNumberToBoolean:
5955 * @val: a number
5956 *
5957 * Converts a number to its boolean value
5958 *
5959 * Returns the boolean value
5960 */
5961int
5962xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005963 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005964 return(0);
5965 return(1);
5966}
5967
5968/**
5969 * xmlXPathCastStringToBoolean:
5970 * @val: a string
5971 *
5972 * Converts a string to its boolean value
5973 *
5974 * Returns the boolean value
5975 */
5976int
5977xmlXPathCastStringToBoolean (const xmlChar *val) {
5978 if ((val == NULL) || (xmlStrlen(val) == 0))
5979 return(0);
5980 return(1);
5981}
5982
5983/**
5984 * xmlXPathCastNodeSetToBoolean:
5985 * @ns: a node-set
5986 *
5987 * Converts a node-set to its boolean value
5988 *
5989 * Returns the boolean value
5990 */
5991int
5992xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5993 if ((ns == NULL) || (ns->nodeNr == 0))
5994 return(0);
5995 return(1);
5996}
5997
5998/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005999 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006000 * @val: an XPath object
6001 *
6002 * Converts an XPath object to its boolean value
6003 *
6004 * Returns the boolean value
6005 */
6006int
6007xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6008 int ret = 0;
6009
6010 if (val == NULL)
6011 return(0);
6012 switch (val->type) {
6013 case XPATH_UNDEFINED:
6014#ifdef DEBUG_EXPR
6015 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6016#endif
6017 ret = 0;
6018 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006019 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00006020 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006021 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6022 break;
6023 case XPATH_STRING:
6024 ret = xmlXPathCastStringToBoolean(val->stringval);
6025 break;
6026 case XPATH_NUMBER:
6027 ret = xmlXPathCastNumberToBoolean(val->floatval);
6028 break;
6029 case XPATH_BOOLEAN:
6030 ret = val->boolval;
6031 break;
6032 case XPATH_USERS:
6033 case XPATH_POINT:
6034 case XPATH_RANGE:
6035 case XPATH_LOCATIONSET:
6036 TODO;
6037 ret = 0;
6038 break;
6039 }
6040 return(ret);
6041}
6042
6043
6044/**
6045 * xmlXPathConvertBoolean:
6046 * @val: an XPath object
6047 *
6048 * Converts an existing object to its boolean() equivalent
6049 *
6050 * Returns the new object, the old one is freed (or the operation
6051 * is done directly on @val)
6052 */
6053xmlXPathObjectPtr
6054xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6055 xmlXPathObjectPtr ret;
6056
6057 if (val == NULL)
6058 return(xmlXPathNewBoolean(0));
6059 if (val->type == XPATH_BOOLEAN)
6060 return(val);
6061 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6062 xmlXPathFreeObject(val);
6063 return(ret);
6064}
6065
Owen Taylor3473f882001-02-23 17:55:21 +00006066/************************************************************************
6067 * *
6068 * Routines to handle XPath contexts *
6069 * *
6070 ************************************************************************/
6071
6072/**
6073 * xmlXPathNewContext:
6074 * @doc: the XML document
6075 *
6076 * Create a new xmlXPathContext
6077 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006078 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006079 */
6080xmlXPathContextPtr
6081xmlXPathNewContext(xmlDocPtr doc) {
6082 xmlXPathContextPtr ret;
6083
6084 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6085 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006086 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006087 return(NULL);
6088 }
6089 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6090 ret->doc = doc;
6091 ret->node = NULL;
6092
6093 ret->varHash = NULL;
6094
6095 ret->nb_types = 0;
6096 ret->max_types = 0;
6097 ret->types = NULL;
6098
6099 ret->funcHash = xmlHashCreate(0);
6100
6101 ret->nb_axis = 0;
6102 ret->max_axis = 0;
6103 ret->axis = NULL;
6104
6105 ret->nsHash = NULL;
6106 ret->user = NULL;
6107
6108 ret->contextSize = -1;
6109 ret->proximityPosition = -1;
6110
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006111#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006112 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006113 xmlXPathFreeContext(ret);
6114 return(NULL);
6115 }
6116#endif
6117
Daniel Veillard45490ae2008-07-29 09:13:19 +00006118 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006119
Owen Taylor3473f882001-02-23 17:55:21 +00006120 return(ret);
6121}
6122
6123/**
6124 * xmlXPathFreeContext:
6125 * @ctxt: the context to free
6126 *
6127 * Free up an xmlXPathContext
6128 */
6129void
6130xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006131 if (ctxt == NULL) return;
6132
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006133 if (ctxt->cache != NULL)
6134 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006135 xmlXPathRegisteredNsCleanup(ctxt);
6136 xmlXPathRegisteredFuncsCleanup(ctxt);
6137 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006138 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006139 xmlFree(ctxt);
6140}
6141
6142/************************************************************************
6143 * *
6144 * Routines to handle XPath parser contexts *
6145 * *
6146 ************************************************************************/
6147
6148#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006149 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006150 __xmlRaiseError(NULL, NULL, NULL, \
6151 NULL, NULL, XML_FROM_XPATH, \
6152 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6153 __FILE__, __LINE__, \
6154 NULL, NULL, NULL, 0, 0, \
6155 "NULL context pointer\n"); \
6156 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006157 } \
6158
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006159#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006160 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006161 __xmlRaiseError(NULL, NULL, NULL, \
6162 NULL, NULL, XML_FROM_XPATH, \
6163 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6164 __FILE__, __LINE__, \
6165 NULL, NULL, NULL, 0, 0, \
6166 "NULL context pointer\n"); \
6167 return(-1); \
6168 } \
6169
Owen Taylor3473f882001-02-23 17:55:21 +00006170
6171#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006172 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006173 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006174 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006175 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006176 }
Owen Taylor3473f882001-02-23 17:55:21 +00006177
6178
6179/**
6180 * xmlXPathNewParserContext:
6181 * @str: the XPath expression
6182 * @ctxt: the XPath context
6183 *
6184 * Create a new xmlXPathParserContext
6185 *
6186 * Returns the xmlXPathParserContext just allocated.
6187 */
6188xmlXPathParserContextPtr
6189xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6190 xmlXPathParserContextPtr ret;
6191
6192 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6193 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006194 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006195 return(NULL);
6196 }
6197 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6198 ret->cur = ret->base = str;
6199 ret->context = ctxt;
6200
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006201 ret->comp = xmlXPathNewCompExpr();
6202 if (ret->comp == NULL) {
6203 xmlFree(ret->valueTab);
6204 xmlFree(ret);
6205 return(NULL);
6206 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006207 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6208 ret->comp->dict = ctxt->dict;
6209 xmlDictReference(ret->comp->dict);
6210 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006211
6212 return(ret);
6213}
6214
6215/**
6216 * xmlXPathCompParserContext:
6217 * @comp: the XPath compiled expression
6218 * @ctxt: the XPath context
6219 *
6220 * Create a new xmlXPathParserContext when processing a compiled expression
6221 *
6222 * Returns the xmlXPathParserContext just allocated.
6223 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006224static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006225xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6226 xmlXPathParserContextPtr ret;
6227
6228 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6229 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006230 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006231 return(NULL);
6232 }
6233 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6234
Owen Taylor3473f882001-02-23 17:55:21 +00006235 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006236 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006237 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006238 if (ret->valueTab == NULL) {
6239 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006240 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006241 return(NULL);
6242 }
Owen Taylor3473f882001-02-23 17:55:21 +00006243 ret->valueNr = 0;
6244 ret->valueMax = 10;
6245 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006246 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006247
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006248 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006249 ret->comp = comp;
6250
Owen Taylor3473f882001-02-23 17:55:21 +00006251 return(ret);
6252}
6253
6254/**
6255 * xmlXPathFreeParserContext:
6256 * @ctxt: the context to free
6257 *
6258 * Free up an xmlXPathParserContext
6259 */
6260void
6261xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6262 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006263 xmlFree(ctxt->valueTab);
6264 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006265 if (ctxt->comp != NULL) {
6266#ifdef XPATH_STREAMING
6267 if (ctxt->comp->stream != NULL) {
6268 xmlFreePatternList(ctxt->comp->stream);
6269 ctxt->comp->stream = NULL;
6270 }
6271#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006272 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006273 }
Owen Taylor3473f882001-02-23 17:55:21 +00006274 xmlFree(ctxt);
6275}
6276
6277/************************************************************************
6278 * *
6279 * The implicit core function library *
6280 * *
6281 ************************************************************************/
6282
Owen Taylor3473f882001-02-23 17:55:21 +00006283/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006284 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006285 * @node: a node pointer
6286 *
6287 * Function computing the beginning of the string value of the node,
6288 * used to speed up comparisons
6289 *
6290 * Returns an int usable as a hash
6291 */
6292static unsigned int
6293xmlXPathNodeValHash(xmlNodePtr node) {
6294 int len = 2;
6295 const xmlChar * string = NULL;
6296 xmlNodePtr tmp = NULL;
6297 unsigned int ret = 0;
6298
6299 if (node == NULL)
6300 return(0);
6301
Daniel Veillard9adc0462003-03-24 18:39:54 +00006302 if (node->type == XML_DOCUMENT_NODE) {
6303 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6304 if (tmp == NULL)
6305 node = node->children;
6306 else
6307 node = tmp;
6308
6309 if (node == NULL)
6310 return(0);
6311 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006312
6313 switch (node->type) {
6314 case XML_COMMENT_NODE:
6315 case XML_PI_NODE:
6316 case XML_CDATA_SECTION_NODE:
6317 case XML_TEXT_NODE:
6318 string = node->content;
6319 if (string == NULL)
6320 return(0);
6321 if (string[0] == 0)
6322 return(0);
6323 return(((unsigned int) string[0]) +
6324 (((unsigned int) string[1]) << 8));
6325 case XML_NAMESPACE_DECL:
6326 string = ((xmlNsPtr)node)->href;
6327 if (string == NULL)
6328 return(0);
6329 if (string[0] == 0)
6330 return(0);
6331 return(((unsigned int) string[0]) +
6332 (((unsigned int) string[1]) << 8));
6333 case XML_ATTRIBUTE_NODE:
6334 tmp = ((xmlAttrPtr) node)->children;
6335 break;
6336 case XML_ELEMENT_NODE:
6337 tmp = node->children;
6338 break;
6339 default:
6340 return(0);
6341 }
6342 while (tmp != NULL) {
6343 switch (tmp->type) {
6344 case XML_COMMENT_NODE:
6345 case XML_PI_NODE:
6346 case XML_CDATA_SECTION_NODE:
6347 case XML_TEXT_NODE:
6348 string = tmp->content;
6349 break;
6350 case XML_NAMESPACE_DECL:
6351 string = ((xmlNsPtr)tmp)->href;
6352 break;
6353 default:
6354 break;
6355 }
6356 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006357 if (len == 1) {
6358 return(ret + (((unsigned int) string[0]) << 8));
6359 }
6360 if (string[1] == 0) {
6361 len = 1;
6362 ret = (unsigned int) string[0];
6363 } else {
6364 return(((unsigned int) string[0]) +
6365 (((unsigned int) string[1]) << 8));
6366 }
6367 }
6368 /*
6369 * Skip to next node
6370 */
6371 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6372 if (tmp->children->type != XML_ENTITY_DECL) {
6373 tmp = tmp->children;
6374 continue;
6375 }
6376 }
6377 if (tmp == node)
6378 break;
6379
6380 if (tmp->next != NULL) {
6381 tmp = tmp->next;
6382 continue;
6383 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006384
Daniel Veillardf06307e2001-07-03 10:35:50 +00006385 do {
6386 tmp = tmp->parent;
6387 if (tmp == NULL)
6388 break;
6389 if (tmp == node) {
6390 tmp = NULL;
6391 break;
6392 }
6393 if (tmp->next != NULL) {
6394 tmp = tmp->next;
6395 break;
6396 }
6397 } while (tmp != NULL);
6398 }
6399 return(ret);
6400}
6401
6402/**
6403 * xmlXPathStringHash:
6404 * @string: a string
6405 *
6406 * Function computing the beginning of the string value of the node,
6407 * used to speed up comparisons
6408 *
6409 * Returns an int usable as a hash
6410 */
6411static unsigned int
6412xmlXPathStringHash(const xmlChar * string) {
6413 if (string == NULL)
6414 return((unsigned int) 0);
6415 if (string[0] == 0)
6416 return(0);
6417 return(((unsigned int) string[0]) +
6418 (((unsigned int) string[1]) << 8));
6419}
6420
6421/**
Owen Taylor3473f882001-02-23 17:55:21 +00006422 * xmlXPathCompareNodeSetFloat:
6423 * @ctxt: the XPath Parser context
6424 * @inf: less than (1) or greater than (0)
6425 * @strict: is the comparison strict
6426 * @arg: the node set
6427 * @f: the value
6428 *
6429 * Implement the compare operation between a nodeset and a number
6430 * @ns < @val (1, 1, ...
6431 * @ns <= @val (1, 0, ...
6432 * @ns > @val (0, 1, ...
6433 * @ns >= @val (0, 0, ...
6434 *
6435 * If one object to be compared is a node-set and the other is a number,
6436 * then the comparison will be true if and only if there is a node in the
6437 * node-set such that the result of performing the comparison on the number
6438 * to be compared and on the result of converting the string-value of that
6439 * node to a number using the number function is true.
6440 *
6441 * Returns 0 or 1 depending on the results of the test.
6442 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006443static int
Owen Taylor3473f882001-02-23 17:55:21 +00006444xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6445 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6446 int i, ret = 0;
6447 xmlNodeSetPtr ns;
6448 xmlChar *str2;
6449
6450 if ((f == NULL) || (arg == NULL) ||
6451 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006452 xmlXPathReleaseObject(ctxt->context, arg);
6453 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006454 return(0);
6455 }
6456 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006457 if (ns != NULL) {
6458 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006459 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006460 if (str2 != NULL) {
6461 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006462 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006463 xmlFree(str2);
6464 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006465 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006466 ret = xmlXPathCompareValues(ctxt, inf, strict);
6467 if (ret)
6468 break;
6469 }
6470 }
Owen Taylor3473f882001-02-23 17:55:21 +00006471 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006472 xmlXPathReleaseObject(ctxt->context, arg);
6473 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006474 return(ret);
6475}
6476
6477/**
6478 * xmlXPathCompareNodeSetString:
6479 * @ctxt: the XPath Parser context
6480 * @inf: less than (1) or greater than (0)
6481 * @strict: is the comparison strict
6482 * @arg: the node set
6483 * @s: the value
6484 *
6485 * Implement the compare operation between a nodeset and a string
6486 * @ns < @val (1, 1, ...
6487 * @ns <= @val (1, 0, ...
6488 * @ns > @val (0, 1, ...
6489 * @ns >= @val (0, 0, ...
6490 *
6491 * If one object to be compared is a node-set and the other is a string,
6492 * then the comparison will be true if and only if there is a node in
6493 * the node-set such that the result of performing the comparison on the
6494 * string-value of the node and the other string is true.
6495 *
6496 * Returns 0 or 1 depending on the results of the test.
6497 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006498static int
Owen Taylor3473f882001-02-23 17:55:21 +00006499xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6500 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6501 int i, ret = 0;
6502 xmlNodeSetPtr ns;
6503 xmlChar *str2;
6504
6505 if ((s == NULL) || (arg == NULL) ||
6506 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006507 xmlXPathReleaseObject(ctxt->context, arg);
6508 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006509 return(0);
6510 }
6511 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006512 if (ns != NULL) {
6513 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006514 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006515 if (str2 != NULL) {
6516 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006517 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006518 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006519 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006520 ret = xmlXPathCompareValues(ctxt, inf, strict);
6521 if (ret)
6522 break;
6523 }
6524 }
Owen Taylor3473f882001-02-23 17:55:21 +00006525 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006526 xmlXPathReleaseObject(ctxt->context, arg);
6527 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006528 return(ret);
6529}
6530
6531/**
6532 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006533 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006534 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006535 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006536 * @arg2: the second node set object
6537 *
6538 * Implement the compare operation on nodesets:
6539 *
6540 * If both objects to be compared are node-sets, then the comparison
6541 * will be true if and only if there is a node in the first node-set
6542 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006543 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006544 * ....
6545 * When neither object to be compared is a node-set and the operator
6546 * is <=, <, >= or >, then the objects are compared by converting both
6547 * objects to numbers and comparing the numbers according to IEEE 754.
6548 * ....
6549 * The number function converts its argument to a number as follows:
6550 * - a string that consists of optional whitespace followed by an
6551 * optional minus sign followed by a Number followed by whitespace
6552 * is converted to the IEEE 754 number that is nearest (according
6553 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6554 * represented by the string; any other string is converted to NaN
6555 *
6556 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006557 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006558 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006559static int
6560xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006561 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6562 int i, j, init = 0;
6563 double val1;
6564 double *values2;
6565 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006566 xmlNodeSetPtr ns1;
6567 xmlNodeSetPtr ns2;
6568
6569 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006570 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6571 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006572 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006573 }
Owen Taylor3473f882001-02-23 17:55:21 +00006574 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006575 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6576 xmlXPathFreeObject(arg1);
6577 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006578 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006579 }
Owen Taylor3473f882001-02-23 17:55:21 +00006580
6581 ns1 = arg1->nodesetval;
6582 ns2 = arg2->nodesetval;
6583
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006584 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006585 xmlXPathFreeObject(arg1);
6586 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006587 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006588 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006589 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006590 xmlXPathFreeObject(arg1);
6591 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006592 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006593 }
Owen Taylor3473f882001-02-23 17:55:21 +00006594
6595 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6596 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006597 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006598 xmlXPathFreeObject(arg1);
6599 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006600 return(0);
6601 }
6602 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006603 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006604 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006605 continue;
6606 for (j = 0;j < ns2->nodeNr;j++) {
6607 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006608 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006609 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006610 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006611 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006612 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006613 ret = (val1 < values2[j]);
6614 else if (inf && !strict)
6615 ret = (val1 <= values2[j]);
6616 else if (!inf && strict)
6617 ret = (val1 > values2[j]);
6618 else if (!inf && !strict)
6619 ret = (val1 >= values2[j]);
6620 if (ret)
6621 break;
6622 }
6623 if (ret)
6624 break;
6625 init = 1;
6626 }
6627 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006628 xmlXPathFreeObject(arg1);
6629 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006630 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006631}
6632
6633/**
6634 * xmlXPathCompareNodeSetValue:
6635 * @ctxt: the XPath Parser context
6636 * @inf: less than (1) or greater than (0)
6637 * @strict: is the comparison strict
6638 * @arg: the node set
6639 * @val: the value
6640 *
6641 * Implement the compare operation between a nodeset and a value
6642 * @ns < @val (1, 1, ...
6643 * @ns <= @val (1, 0, ...
6644 * @ns > @val (0, 1, ...
6645 * @ns >= @val (0, 0, ...
6646 *
6647 * If one object to be compared is a node-set and the other is a boolean,
6648 * then the comparison will be true if and only if the result of performing
6649 * the comparison on the boolean and on the result of converting
6650 * the node-set to a boolean using the boolean function is true.
6651 *
6652 * Returns 0 or 1 depending on the results of the test.
6653 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006654static int
Owen Taylor3473f882001-02-23 17:55:21 +00006655xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6656 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6657 if ((val == NULL) || (arg == NULL) ||
6658 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6659 return(0);
6660
6661 switch(val->type) {
6662 case XPATH_NUMBER:
6663 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6664 case XPATH_NODESET:
6665 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006666 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006667 case XPATH_STRING:
6668 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6669 case XPATH_BOOLEAN:
6670 valuePush(ctxt, arg);
6671 xmlXPathBooleanFunction(ctxt, 1);
6672 valuePush(ctxt, val);
6673 return(xmlXPathCompareValues(ctxt, inf, strict));
6674 default:
6675 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006676 }
6677 return(0);
6678}
6679
6680/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006681 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006682 * @arg: the nodeset object argument
6683 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006684 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006685 *
6686 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6687 * If one object to be compared is a node-set and the other is a string,
6688 * then the comparison will be true if and only if there is a node in
6689 * the node-set such that the result of performing the comparison on the
6690 * string-value of the node and the other string is true.
6691 *
6692 * Returns 0 or 1 depending on the results of the test.
6693 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006694static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006695xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006696{
Owen Taylor3473f882001-02-23 17:55:21 +00006697 int i;
6698 xmlNodeSetPtr ns;
6699 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006700 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006701
6702 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006703 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6704 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006705 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006706 /*
6707 * A NULL nodeset compared with a string is always false
6708 * (since there is no node equal, and no node not equal)
6709 */
6710 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006711 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006712 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006713 for (i = 0; i < ns->nodeNr; i++) {
6714 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6715 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6716 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6717 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006718 if (neq)
6719 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006720 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006721 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6722 if (neq)
6723 continue;
6724 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006725 } else if (neq) {
6726 if (str2 != NULL)
6727 xmlFree(str2);
6728 return (1);
6729 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006730 if (str2 != NULL)
6731 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006732 } else if (neq)
6733 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006734 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006735 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006736}
6737
6738/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006739 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006740 * @arg: the nodeset object argument
6741 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006742 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006743 *
6744 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6745 * If one object to be compared is a node-set and the other is a number,
6746 * then the comparison will be true if and only if there is a node in
6747 * the node-set such that the result of performing the comparison on the
6748 * number to be compared and on the result of converting the string-value
6749 * of that node to a number using the number function is true.
6750 *
6751 * Returns 0 or 1 depending on the results of the test.
6752 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006753static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006754xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6755 xmlXPathObjectPtr arg, double f, int neq) {
6756 int i, ret=0;
6757 xmlNodeSetPtr ns;
6758 xmlChar *str2;
6759 xmlXPathObjectPtr val;
6760 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006761
6762 if ((arg == NULL) ||
6763 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6764 return(0);
6765
William M. Brack0c022ad2002-07-12 00:56:01 +00006766 ns = arg->nodesetval;
6767 if (ns != NULL) {
6768 for (i=0;i<ns->nodeNr;i++) {
6769 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6770 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006771 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006772 xmlFree(str2);
6773 xmlXPathNumberFunction(ctxt, 1);
6774 val = valuePop(ctxt);
6775 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006776 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006777 if (!xmlXPathIsNaN(v)) {
6778 if ((!neq) && (v==f)) {
6779 ret = 1;
6780 break;
6781 } else if ((neq) && (v!=f)) {
6782 ret = 1;
6783 break;
6784 }
William M. Brack32f0f712005-07-14 07:00:33 +00006785 } else { /* NaN is unequal to any value */
6786 if (neq)
6787 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006788 }
6789 }
6790 }
6791 }
6792
6793 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006794}
6795
6796
6797/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006798 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006799 * @arg1: first nodeset object argument
6800 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006801 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006802 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006803 * Implement the equal / not equal operation on XPath nodesets:
6804 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006805 * If both objects to be compared are node-sets, then the comparison
6806 * will be true if and only if there is a node in the first node-set and
6807 * a node in the second node-set such that the result of performing the
6808 * comparison on the string-values of the two nodes is true.
6809 *
6810 * (needless to say, this is a costly operation)
6811 *
6812 * Returns 0 or 1 depending on the results of the test.
6813 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006814static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006815xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006816 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006817 unsigned int *hashs1;
6818 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006819 xmlChar **values1;
6820 xmlChar **values2;
6821 int ret = 0;
6822 xmlNodeSetPtr ns1;
6823 xmlNodeSetPtr ns2;
6824
6825 if ((arg1 == NULL) ||
6826 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6827 return(0);
6828 if ((arg2 == NULL) ||
6829 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6830 return(0);
6831
6832 ns1 = arg1->nodesetval;
6833 ns2 = arg2->nodesetval;
6834
Daniel Veillard911f49a2001-04-07 15:39:35 +00006835 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006836 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006837 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006838 return(0);
6839
6840 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006841 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006842 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006843 if (neq == 0)
6844 for (i = 0;i < ns1->nodeNr;i++)
6845 for (j = 0;j < ns2->nodeNr;j++)
6846 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6847 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006848
6849 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006850 if (values1 == NULL) {
6851 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006852 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006853 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006854 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6855 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006856 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006857 xmlFree(values1);
6858 return(0);
6859 }
Owen Taylor3473f882001-02-23 17:55:21 +00006860 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6861 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6862 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006863 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006864 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006865 xmlFree(values1);
6866 return(0);
6867 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006868 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6869 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006870 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006871 xmlFree(hashs1);
6872 xmlFree(values1);
6873 xmlFree(values2);
6874 return(0);
6875 }
Owen Taylor3473f882001-02-23 17:55:21 +00006876 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6877 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006878 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006879 for (j = 0;j < ns2->nodeNr;j++) {
6880 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006881 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006882 if (hashs1[i] != hashs2[j]) {
6883 if (neq) {
6884 ret = 1;
6885 break;
6886 }
6887 }
6888 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006889 if (values1[i] == NULL)
6890 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6891 if (values2[j] == NULL)
6892 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006893 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006894 if (ret)
6895 break;
6896 }
Owen Taylor3473f882001-02-23 17:55:21 +00006897 }
6898 if (ret)
6899 break;
6900 }
6901 for (i = 0;i < ns1->nodeNr;i++)
6902 if (values1[i] != NULL)
6903 xmlFree(values1[i]);
6904 for (j = 0;j < ns2->nodeNr;j++)
6905 if (values2[j] != NULL)
6906 xmlFree(values2[j]);
6907 xmlFree(values1);
6908 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006909 xmlFree(hashs1);
6910 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006911 return(ret);
6912}
6913
William M. Brack0c022ad2002-07-12 00:56:01 +00006914static int
6915xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6916 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006917 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006918 /*
6919 *At this point we are assured neither arg1 nor arg2
6920 *is a nodeset, so we can just pick the appropriate routine.
6921 */
Owen Taylor3473f882001-02-23 17:55:21 +00006922 switch (arg1->type) {
6923 case XPATH_UNDEFINED:
6924#ifdef DEBUG_EXPR
6925 xmlGenericError(xmlGenericErrorContext,
6926 "Equal: undefined\n");
6927#endif
6928 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006929 case XPATH_BOOLEAN:
6930 switch (arg2->type) {
6931 case XPATH_UNDEFINED:
6932#ifdef DEBUG_EXPR
6933 xmlGenericError(xmlGenericErrorContext,
6934 "Equal: undefined\n");
6935#endif
6936 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006937 case XPATH_BOOLEAN:
6938#ifdef DEBUG_EXPR
6939 xmlGenericError(xmlGenericErrorContext,
6940 "Equal: %d boolean %d \n",
6941 arg1->boolval, arg2->boolval);
6942#endif
6943 ret = (arg1->boolval == arg2->boolval);
6944 break;
6945 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006946 ret = (arg1->boolval ==
6947 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006948 break;
6949 case XPATH_STRING:
6950 if ((arg2->stringval == NULL) ||
6951 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006952 else
Owen Taylor3473f882001-02-23 17:55:21 +00006953 ret = 1;
6954 ret = (arg1->boolval == ret);
6955 break;
6956 case XPATH_USERS:
6957 case XPATH_POINT:
6958 case XPATH_RANGE:
6959 case XPATH_LOCATIONSET:
6960 TODO
6961 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006962 case XPATH_NODESET:
6963 case XPATH_XSLT_TREE:
6964 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006965 }
6966 break;
6967 case XPATH_NUMBER:
6968 switch (arg2->type) {
6969 case XPATH_UNDEFINED:
6970#ifdef DEBUG_EXPR
6971 xmlGenericError(xmlGenericErrorContext,
6972 "Equal: undefined\n");
6973#endif
6974 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006975 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006976 ret = (arg2->boolval==
6977 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006978 break;
6979 case XPATH_STRING:
6980 valuePush(ctxt, arg2);
6981 xmlXPathNumberFunction(ctxt, 1);
6982 arg2 = valuePop(ctxt);
6983 /* no break on purpose */
6984 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006985 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006986 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00006987 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006988 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006989 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6990 if (xmlXPathIsInf(arg2->floatval) == 1)
6991 ret = 1;
6992 else
6993 ret = 0;
6994 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6995 if (xmlXPathIsInf(arg2->floatval) == -1)
6996 ret = 1;
6997 else
6998 ret = 0;
6999 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7000 if (xmlXPathIsInf(arg1->floatval) == 1)
7001 ret = 1;
7002 else
7003 ret = 0;
7004 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7005 if (xmlXPathIsInf(arg1->floatval) == -1)
7006 ret = 1;
7007 else
7008 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007009 } else {
7010 ret = (arg1->floatval == arg2->floatval);
7011 }
Owen Taylor3473f882001-02-23 17:55:21 +00007012 break;
7013 case XPATH_USERS:
7014 case XPATH_POINT:
7015 case XPATH_RANGE:
7016 case XPATH_LOCATIONSET:
7017 TODO
7018 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007019 case XPATH_NODESET:
7020 case XPATH_XSLT_TREE:
7021 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007022 }
7023 break;
7024 case XPATH_STRING:
7025 switch (arg2->type) {
7026 case XPATH_UNDEFINED:
7027#ifdef DEBUG_EXPR
7028 xmlGenericError(xmlGenericErrorContext,
7029 "Equal: undefined\n");
7030#endif
7031 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007032 case XPATH_BOOLEAN:
7033 if ((arg1->stringval == NULL) ||
7034 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007035 else
Owen Taylor3473f882001-02-23 17:55:21 +00007036 ret = 1;
7037 ret = (arg2->boolval == ret);
7038 break;
7039 case XPATH_STRING:
7040 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7041 break;
7042 case XPATH_NUMBER:
7043 valuePush(ctxt, arg1);
7044 xmlXPathNumberFunction(ctxt, 1);
7045 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007046 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007047 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007048 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007049 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007050 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7051 if (xmlXPathIsInf(arg2->floatval) == 1)
7052 ret = 1;
7053 else
7054 ret = 0;
7055 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7056 if (xmlXPathIsInf(arg2->floatval) == -1)
7057 ret = 1;
7058 else
7059 ret = 0;
7060 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7061 if (xmlXPathIsInf(arg1->floatval) == 1)
7062 ret = 1;
7063 else
7064 ret = 0;
7065 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7066 if (xmlXPathIsInf(arg1->floatval) == -1)
7067 ret = 1;
7068 else
7069 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007070 } else {
7071 ret = (arg1->floatval == arg2->floatval);
7072 }
Owen Taylor3473f882001-02-23 17:55:21 +00007073 break;
7074 case XPATH_USERS:
7075 case XPATH_POINT:
7076 case XPATH_RANGE:
7077 case XPATH_LOCATIONSET:
7078 TODO
7079 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007080 case XPATH_NODESET:
7081 case XPATH_XSLT_TREE:
7082 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007083 }
7084 break;
7085 case XPATH_USERS:
7086 case XPATH_POINT:
7087 case XPATH_RANGE:
7088 case XPATH_LOCATIONSET:
7089 TODO
7090 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007091 case XPATH_NODESET:
7092 case XPATH_XSLT_TREE:
7093 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007094 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007095 xmlXPathReleaseObject(ctxt->context, arg1);
7096 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007097 return(ret);
7098}
7099
William M. Brack0c022ad2002-07-12 00:56:01 +00007100/**
7101 * xmlXPathEqualValues:
7102 * @ctxt: the XPath Parser context
7103 *
7104 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7105 *
7106 * Returns 0 or 1 depending on the results of the test.
7107 */
7108int
7109xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7110 xmlXPathObjectPtr arg1, arg2, argtmp;
7111 int ret = 0;
7112
Daniel Veillard6128c012004-11-08 17:16:15 +00007113 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007114 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007115 arg1 = valuePop(ctxt);
7116 if ((arg1 == NULL) || (arg2 == NULL)) {
7117 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007118 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007119 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007120 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007121 XP_ERROR0(XPATH_INVALID_OPERAND);
7122 }
7123
7124 if (arg1 == arg2) {
7125#ifdef DEBUG_EXPR
7126 xmlGenericError(xmlGenericErrorContext,
7127 "Equal: by pointer\n");
7128#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007129 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007130 return(1);
7131 }
7132
7133 /*
7134 *If either argument is a nodeset, it's a 'special case'
7135 */
7136 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7137 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7138 /*
7139 *Hack it to assure arg1 is the nodeset
7140 */
7141 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7142 argtmp = arg2;
7143 arg2 = arg1;
7144 arg1 = argtmp;
7145 }
7146 switch (arg2->type) {
7147 case XPATH_UNDEFINED:
7148#ifdef DEBUG_EXPR
7149 xmlGenericError(xmlGenericErrorContext,
7150 "Equal: undefined\n");
7151#endif
7152 break;
7153 case XPATH_NODESET:
7154 case XPATH_XSLT_TREE:
7155 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7156 break;
7157 case XPATH_BOOLEAN:
7158 if ((arg1->nodesetval == NULL) ||
7159 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007160 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007161 ret = 1;
7162 ret = (ret == arg2->boolval);
7163 break;
7164 case XPATH_NUMBER:
7165 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7166 break;
7167 case XPATH_STRING:
7168 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7169 break;
7170 case XPATH_USERS:
7171 case XPATH_POINT:
7172 case XPATH_RANGE:
7173 case XPATH_LOCATIONSET:
7174 TODO
7175 break;
7176 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007177 xmlXPathReleaseObject(ctxt->context, arg1);
7178 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007179 return(ret);
7180 }
7181
7182 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7183}
7184
7185/**
7186 * xmlXPathNotEqualValues:
7187 * @ctxt: the XPath Parser context
7188 *
7189 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7190 *
7191 * Returns 0 or 1 depending on the results of the test.
7192 */
7193int
7194xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7195 xmlXPathObjectPtr arg1, arg2, argtmp;
7196 int ret = 0;
7197
Daniel Veillard6128c012004-11-08 17:16:15 +00007198 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007199 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007200 arg1 = valuePop(ctxt);
7201 if ((arg1 == NULL) || (arg2 == NULL)) {
7202 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007203 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007204 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007205 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007206 XP_ERROR0(XPATH_INVALID_OPERAND);
7207 }
7208
7209 if (arg1 == arg2) {
7210#ifdef DEBUG_EXPR
7211 xmlGenericError(xmlGenericErrorContext,
7212 "NotEqual: by pointer\n");
7213#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007214 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007215 return(0);
7216 }
7217
7218 /*
7219 *If either argument is a nodeset, it's a 'special case'
7220 */
7221 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7222 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7223 /*
7224 *Hack it to assure arg1 is the nodeset
7225 */
7226 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7227 argtmp = arg2;
7228 arg2 = arg1;
7229 arg1 = argtmp;
7230 }
7231 switch (arg2->type) {
7232 case XPATH_UNDEFINED:
7233#ifdef DEBUG_EXPR
7234 xmlGenericError(xmlGenericErrorContext,
7235 "NotEqual: undefined\n");
7236#endif
7237 break;
7238 case XPATH_NODESET:
7239 case XPATH_XSLT_TREE:
7240 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7241 break;
7242 case XPATH_BOOLEAN:
7243 if ((arg1->nodesetval == NULL) ||
7244 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007245 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007246 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007247 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007248 break;
7249 case XPATH_NUMBER:
7250 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7251 break;
7252 case XPATH_STRING:
7253 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7254 break;
7255 case XPATH_USERS:
7256 case XPATH_POINT:
7257 case XPATH_RANGE:
7258 case XPATH_LOCATIONSET:
7259 TODO
7260 break;
7261 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007262 xmlXPathReleaseObject(ctxt->context, arg1);
7263 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007264 return(ret);
7265 }
7266
7267 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7268}
Owen Taylor3473f882001-02-23 17:55:21 +00007269
7270/**
7271 * xmlXPathCompareValues:
7272 * @ctxt: the XPath Parser context
7273 * @inf: less than (1) or greater than (0)
7274 * @strict: is the comparison strict
7275 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007276 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007277 * @arg1 < @arg2 (1, 1, ...
7278 * @arg1 <= @arg2 (1, 0, ...
7279 * @arg1 > @arg2 (0, 1, ...
7280 * @arg1 >= @arg2 (0, 0, ...
7281 *
7282 * When neither object to be compared is a node-set and the operator is
7283 * <=, <, >=, >, then the objects are compared by converted both objects
7284 * to numbers and comparing the numbers according to IEEE 754. The <
7285 * comparison will be true if and only if the first number is less than the
7286 * second number. The <= comparison will be true if and only if the first
7287 * number is less than or equal to the second number. The > comparison
7288 * will be true if and only if the first number is greater than the second
7289 * number. The >= comparison will be true if and only if the first number
7290 * is greater than or equal to the second number.
7291 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007292 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007293 */
7294int
7295xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007296 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007297 xmlXPathObjectPtr arg1, arg2;
7298
Daniel Veillard6128c012004-11-08 17:16:15 +00007299 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007300 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007301 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007302 if ((arg1 == NULL) || (arg2 == NULL)) {
7303 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007304 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007305 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007306 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007307 XP_ERROR0(XPATH_INVALID_OPERAND);
7308 }
7309
William M. Brack0c022ad2002-07-12 00:56:01 +00007310 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7311 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007312 /*
7313 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7314 * are not freed from within this routine; they will be freed from the
7315 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7316 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007317 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7318 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007319 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007320 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007321 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007322 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7323 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007324 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007325 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7326 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007327 }
7328 }
7329 return(ret);
7330 }
7331
7332 if (arg1->type != XPATH_NUMBER) {
7333 valuePush(ctxt, arg1);
7334 xmlXPathNumberFunction(ctxt, 1);
7335 arg1 = valuePop(ctxt);
7336 }
7337 if (arg1->type != XPATH_NUMBER) {
7338 xmlXPathFreeObject(arg1);
7339 xmlXPathFreeObject(arg2);
7340 XP_ERROR0(XPATH_INVALID_OPERAND);
7341 }
7342 if (arg2->type != XPATH_NUMBER) {
7343 valuePush(ctxt, arg2);
7344 xmlXPathNumberFunction(ctxt, 1);
7345 arg2 = valuePop(ctxt);
7346 }
7347 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007348 xmlXPathReleaseObject(ctxt->context, arg1);
7349 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007350 XP_ERROR0(XPATH_INVALID_OPERAND);
7351 }
7352 /*
7353 * Add tests for infinity and nan
7354 * => feedback on 3.4 for Inf and NaN
7355 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007356 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007357 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007358 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007359 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007360 arg1i=xmlXPathIsInf(arg1->floatval);
7361 arg2i=xmlXPathIsInf(arg2->floatval);
7362 if (inf && strict) {
7363 if ((arg1i == -1 && arg2i != -1) ||
7364 (arg2i == 1 && arg1i != 1)) {
7365 ret = 1;
7366 } else if (arg1i == 0 && arg2i == 0) {
7367 ret = (arg1->floatval < arg2->floatval);
7368 } else {
7369 ret = 0;
7370 }
7371 }
7372 else if (inf && !strict) {
7373 if (arg1i == -1 || arg2i == 1) {
7374 ret = 1;
7375 } else if (arg1i == 0 && arg2i == 0) {
7376 ret = (arg1->floatval <= arg2->floatval);
7377 } else {
7378 ret = 0;
7379 }
7380 }
7381 else if (!inf && strict) {
7382 if ((arg1i == 1 && arg2i != 1) ||
7383 (arg2i == -1 && arg1i != -1)) {
7384 ret = 1;
7385 } else if (arg1i == 0 && arg2i == 0) {
7386 ret = (arg1->floatval > arg2->floatval);
7387 } else {
7388 ret = 0;
7389 }
7390 }
7391 else if (!inf && !strict) {
7392 if (arg1i == 1 || arg2i == -1) {
7393 ret = 1;
7394 } else if (arg1i == 0 && arg2i == 0) {
7395 ret = (arg1->floatval >= arg2->floatval);
7396 } else {
7397 ret = 0;
7398 }
7399 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007400 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007401 xmlXPathReleaseObject(ctxt->context, arg1);
7402 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007403 return(ret);
7404}
7405
7406/**
7407 * xmlXPathValueFlipSign:
7408 * @ctxt: the XPath Parser context
7409 *
7410 * Implement the unary - operation on an XPath object
7411 * The numeric operators convert their operands to numbers as if
7412 * by calling the number function.
7413 */
7414void
7415xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007416 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007417 CAST_TO_NUMBER;
7418 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007419 if (xmlXPathIsNaN(ctxt->value->floatval))
7420 ctxt->value->floatval=xmlXPathNAN;
7421 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7422 ctxt->value->floatval=xmlXPathNINF;
7423 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7424 ctxt->value->floatval=xmlXPathPINF;
7425 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007426 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7427 ctxt->value->floatval = xmlXPathNZERO;
7428 else
7429 ctxt->value->floatval = 0;
7430 }
7431 else
7432 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007433}
7434
7435/**
7436 * xmlXPathAddValues:
7437 * @ctxt: the XPath Parser context
7438 *
7439 * Implement the add operation on XPath objects:
7440 * The numeric operators convert their operands to numbers as if
7441 * by calling the number function.
7442 */
7443void
7444xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7445 xmlXPathObjectPtr arg;
7446 double val;
7447
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007448 arg = valuePop(ctxt);
7449 if (arg == NULL)
7450 XP_ERROR(XPATH_INVALID_OPERAND);
7451 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007452 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007453 CAST_TO_NUMBER;
7454 CHECK_TYPE(XPATH_NUMBER);
7455 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007456}
7457
7458/**
7459 * xmlXPathSubValues:
7460 * @ctxt: the XPath Parser context
7461 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007462 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007463 * The numeric operators convert their operands to numbers as if
7464 * by calling the number function.
7465 */
7466void
7467xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7468 xmlXPathObjectPtr arg;
7469 double val;
7470
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007471 arg = valuePop(ctxt);
7472 if (arg == NULL)
7473 XP_ERROR(XPATH_INVALID_OPERAND);
7474 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007475 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007476 CAST_TO_NUMBER;
7477 CHECK_TYPE(XPATH_NUMBER);
7478 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007479}
7480
7481/**
7482 * xmlXPathMultValues:
7483 * @ctxt: the XPath Parser context
7484 *
7485 * Implement the multiply operation on XPath objects:
7486 * The numeric operators convert their operands to numbers as if
7487 * by calling the number function.
7488 */
7489void
7490xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7491 xmlXPathObjectPtr arg;
7492 double val;
7493
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007494 arg = valuePop(ctxt);
7495 if (arg == NULL)
7496 XP_ERROR(XPATH_INVALID_OPERAND);
7497 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007498 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007499 CAST_TO_NUMBER;
7500 CHECK_TYPE(XPATH_NUMBER);
7501 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007502}
7503
7504/**
7505 * xmlXPathDivValues:
7506 * @ctxt: the XPath Parser context
7507 *
7508 * Implement the div operation on XPath objects @arg1 / @arg2:
7509 * The numeric operators convert their operands to numbers as if
7510 * by calling the number function.
7511 */
7512void
7513xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7514 xmlXPathObjectPtr arg;
7515 double val;
7516
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007517 arg = valuePop(ctxt);
7518 if (arg == NULL)
7519 XP_ERROR(XPATH_INVALID_OPERAND);
7520 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007521 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007522 CAST_TO_NUMBER;
7523 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007524 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7525 ctxt->value->floatval = xmlXPathNAN;
7526 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007527 if (ctxt->value->floatval == 0)
7528 ctxt->value->floatval = xmlXPathNAN;
7529 else if (ctxt->value->floatval > 0)
7530 ctxt->value->floatval = xmlXPathNINF;
7531 else if (ctxt->value->floatval < 0)
7532 ctxt->value->floatval = xmlXPathPINF;
7533 }
7534 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007535 if (ctxt->value->floatval == 0)
7536 ctxt->value->floatval = xmlXPathNAN;
7537 else if (ctxt->value->floatval > 0)
7538 ctxt->value->floatval = xmlXPathPINF;
7539 else if (ctxt->value->floatval < 0)
7540 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007541 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007542 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007543}
7544
7545/**
7546 * xmlXPathModValues:
7547 * @ctxt: the XPath Parser context
7548 *
7549 * Implement the mod operation on XPath objects: @arg1 / @arg2
7550 * The numeric operators convert their operands to numbers as if
7551 * by calling the number function.
7552 */
7553void
7554xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7555 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007556 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007557
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007558 arg = valuePop(ctxt);
7559 if (arg == NULL)
7560 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007561 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007562 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007563 CAST_TO_NUMBER;
7564 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007565 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007566 if (arg2 == 0)
7567 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007568 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007569 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007570 }
Owen Taylor3473f882001-02-23 17:55:21 +00007571}
7572
7573/************************************************************************
7574 * *
7575 * The traversal functions *
7576 * *
7577 ************************************************************************/
7578
Owen Taylor3473f882001-02-23 17:55:21 +00007579/*
7580 * A traversal function enumerates nodes along an axis.
7581 * Initially it must be called with NULL, and it indicates
7582 * termination on the axis by returning NULL.
7583 */
7584typedef xmlNodePtr (*xmlXPathTraversalFunction)
7585 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7586
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007587/*
7588 * xmlXPathTraversalFunctionExt:
7589 * A traversal function enumerates nodes along an axis.
7590 * Initially it must be called with NULL, and it indicates
7591 * termination on the axis by returning NULL.
7592 * The context node of the traversal is specified via @contextNode.
7593 */
7594typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7595 (xmlNodePtr cur, xmlNodePtr contextNode);
7596
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007597/*
7598 * xmlXPathNodeSetMergeFunction:
7599 * Used for merging node sets in xmlXPathCollectAndTest().
7600 */
7601typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7602 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7603
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007604
Owen Taylor3473f882001-02-23 17:55:21 +00007605/**
7606 * xmlXPathNextSelf:
7607 * @ctxt: the XPath Parser context
7608 * @cur: the current node in the traversal
7609 *
7610 * Traversal function for the "self" direction
7611 * The self axis contains just the context node itself
7612 *
7613 * Returns the next element following that axis
7614 */
7615xmlNodePtr
7616xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007617 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007618 if (cur == NULL)
7619 return(ctxt->context->node);
7620 return(NULL);
7621}
7622
7623/**
7624 * xmlXPathNextChild:
7625 * @ctxt: the XPath Parser context
7626 * @cur: the current node in the traversal
7627 *
7628 * Traversal function for the "child" direction
7629 * The child axis contains the children of the context node in document order.
7630 *
7631 * Returns the next element following that axis
7632 */
7633xmlNodePtr
7634xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007635 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007636 if (cur == NULL) {
7637 if (ctxt->context->node == NULL) return(NULL);
7638 switch (ctxt->context->node->type) {
7639 case XML_ELEMENT_NODE:
7640 case XML_TEXT_NODE:
7641 case XML_CDATA_SECTION_NODE:
7642 case XML_ENTITY_REF_NODE:
7643 case XML_ENTITY_NODE:
7644 case XML_PI_NODE:
7645 case XML_COMMENT_NODE:
7646 case XML_NOTATION_NODE:
7647 case XML_DTD_NODE:
7648 return(ctxt->context->node->children);
7649 case XML_DOCUMENT_NODE:
7650 case XML_DOCUMENT_TYPE_NODE:
7651 case XML_DOCUMENT_FRAG_NODE:
7652 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007653#ifdef LIBXML_DOCB_ENABLED
7654 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007655#endif
7656 return(((xmlDocPtr) ctxt->context->node)->children);
7657 case XML_ELEMENT_DECL:
7658 case XML_ATTRIBUTE_DECL:
7659 case XML_ENTITY_DECL:
7660 case XML_ATTRIBUTE_NODE:
7661 case XML_NAMESPACE_DECL:
7662 case XML_XINCLUDE_START:
7663 case XML_XINCLUDE_END:
7664 return(NULL);
7665 }
7666 return(NULL);
7667 }
7668 if ((cur->type == XML_DOCUMENT_NODE) ||
7669 (cur->type == XML_HTML_DOCUMENT_NODE))
7670 return(NULL);
7671 return(cur->next);
7672}
7673
7674/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007675 * xmlXPathNextChildElement:
7676 * @ctxt: the XPath Parser context
7677 * @cur: the current node in the traversal
7678 *
7679 * Traversal function for the "child" direction and nodes of type element.
7680 * The child axis contains the children of the context node in document order.
7681 *
7682 * Returns the next element following that axis
7683 */
7684static xmlNodePtr
7685xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7686 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7687 if (cur == NULL) {
7688 cur = ctxt->context->node;
7689 if (cur == NULL) return(NULL);
7690 /*
7691 * Get the first element child.
7692 */
7693 switch (cur->type) {
7694 case XML_ELEMENT_NODE:
7695 case XML_DOCUMENT_FRAG_NODE:
7696 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7697 case XML_ENTITY_NODE:
7698 cur = cur->children;
7699 if (cur != NULL) {
7700 if (cur->type == XML_ELEMENT_NODE)
7701 return(cur);
7702 do {
7703 cur = cur->next;
7704 } while ((cur != NULL) &&
7705 (cur->type != XML_ELEMENT_NODE));
7706 return(cur);
7707 }
7708 return(NULL);
7709 case XML_DOCUMENT_NODE:
7710 case XML_HTML_DOCUMENT_NODE:
7711#ifdef LIBXML_DOCB_ENABLED
7712 case XML_DOCB_DOCUMENT_NODE:
7713#endif
7714 return(xmlDocGetRootElement((xmlDocPtr) cur));
7715 default:
7716 return(NULL);
7717 }
7718 return(NULL);
7719 }
7720 /*
7721 * Get the next sibling element node.
7722 */
7723 switch (cur->type) {
7724 case XML_ELEMENT_NODE:
7725 case XML_TEXT_NODE:
7726 case XML_ENTITY_REF_NODE:
7727 case XML_ENTITY_NODE:
7728 case XML_CDATA_SECTION_NODE:
7729 case XML_PI_NODE:
7730 case XML_COMMENT_NODE:
7731 case XML_XINCLUDE_END:
7732 break;
7733 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7734 default:
7735 return(NULL);
7736 }
7737 if (cur->next != NULL) {
7738 if (cur->next->type == XML_ELEMENT_NODE)
7739 return(cur->next);
7740 cur = cur->next;
7741 do {
7742 cur = cur->next;
7743 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7744 return(cur);
7745 }
7746 return(NULL);
7747}
7748
7749/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007750 * xmlXPathNextDescendantOrSelfElemParent:
7751 * @ctxt: the XPath Parser context
7752 * @cur: the current node in the traversal
7753 *
7754 * Traversal function for the "descendant-or-self" axis.
7755 * Additionally it returns only nodes which can be parents of
7756 * element nodes.
7757 *
7758 *
7759 * Returns the next element following that axis
7760 */
7761static xmlNodePtr
7762xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7763 xmlNodePtr contextNode)
7764{
7765 if (cur == NULL) {
7766 if (contextNode == NULL)
7767 return(NULL);
7768 switch (contextNode->type) {
7769 case XML_ELEMENT_NODE:
7770 case XML_XINCLUDE_START:
7771 case XML_DOCUMENT_FRAG_NODE:
7772 case XML_DOCUMENT_NODE:
7773#ifdef LIBXML_DOCB_ENABLED
7774 case XML_DOCB_DOCUMENT_NODE:
7775#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00007776 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007777 return(contextNode);
7778 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007779 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007780 }
7781 return(NULL);
7782 } else {
7783 xmlNodePtr start = cur;
7784
7785 while (cur != NULL) {
7786 switch (cur->type) {
7787 case XML_ELEMENT_NODE:
7788 /* TODO: OK to have XInclude here? */
7789 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007790 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007791 if (cur != start)
7792 return(cur);
7793 if (cur->children != NULL) {
7794 cur = cur->children;
7795 continue;
7796 }
7797 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007798 /* Not sure if we need those here. */
7799 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007800#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007801 case XML_DOCB_DOCUMENT_NODE:
7802#endif
7803 case XML_HTML_DOCUMENT_NODE:
7804 if (cur != start)
7805 return(cur);
7806 return(xmlDocGetRootElement((xmlDocPtr) cur));
7807 default:
7808 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007809 }
7810
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007811next_sibling:
7812 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007813 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007814 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007815 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007816 } else {
7817 cur = cur->parent;
7818 goto next_sibling;
7819 }
7820 }
7821 }
7822 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007823}
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007824
7825/**
Owen Taylor3473f882001-02-23 17:55:21 +00007826 * xmlXPathNextDescendant:
7827 * @ctxt: the XPath Parser context
7828 * @cur: the current node in the traversal
7829 *
7830 * Traversal function for the "descendant" direction
7831 * the descendant axis contains the descendants of the context node in document
7832 * order; a descendant is a child or a child of a child and so on.
7833 *
7834 * Returns the next element following that axis
7835 */
7836xmlNodePtr
7837xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007838 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007839 if (cur == NULL) {
7840 if (ctxt->context->node == NULL)
7841 return(NULL);
7842 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7843 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7844 return(NULL);
7845
7846 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7847 return(ctxt->context->doc->children);
7848 return(ctxt->context->node->children);
7849 }
7850
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007851 if (cur->type == XML_NAMESPACE_DECL)
7852 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007853 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007854 /*
7855 * Do not descend on entities declarations
7856 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007857 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007858 cur = cur->children;
7859 /*
7860 * Skip DTDs
7861 */
7862 if (cur->type != XML_DTD_NODE)
7863 return(cur);
7864 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007865 }
7866
7867 if (cur == ctxt->context->node) return(NULL);
7868
Daniel Veillard68e9e742002-11-16 15:35:11 +00007869 while (cur->next != NULL) {
7870 cur = cur->next;
7871 if ((cur->type != XML_ENTITY_DECL) &&
7872 (cur->type != XML_DTD_NODE))
7873 return(cur);
7874 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007875
Owen Taylor3473f882001-02-23 17:55:21 +00007876 do {
7877 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007878 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007879 if (cur == ctxt->context->node) return(NULL);
7880 if (cur->next != NULL) {
7881 cur = cur->next;
7882 return(cur);
7883 }
7884 } while (cur != NULL);
7885 return(cur);
7886}
7887
7888/**
7889 * xmlXPathNextDescendantOrSelf:
7890 * @ctxt: the XPath Parser context
7891 * @cur: the current node in the traversal
7892 *
7893 * Traversal function for the "descendant-or-self" direction
7894 * the descendant-or-self axis contains the context node and the descendants
7895 * of the context node in document order; thus the context node is the first
7896 * node on the axis, and the first child of the context node is the second node
7897 * on the axis
7898 *
7899 * Returns the next element following that axis
7900 */
7901xmlNodePtr
7902xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007903 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007904 if (cur == NULL) {
7905 if (ctxt->context->node == NULL)
7906 return(NULL);
7907 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7908 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7909 return(NULL);
7910 return(ctxt->context->node);
7911 }
7912
7913 return(xmlXPathNextDescendant(ctxt, cur));
7914}
7915
7916/**
7917 * xmlXPathNextParent:
7918 * @ctxt: the XPath Parser context
7919 * @cur: the current node in the traversal
7920 *
7921 * Traversal function for the "parent" direction
7922 * The parent axis contains the parent of the context node, if there is one.
7923 *
7924 * Returns the next element following that axis
7925 */
7926xmlNodePtr
7927xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007928 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007929 /*
7930 * the parent of an attribute or namespace node is the element
7931 * to which the attribute or namespace node is attached
7932 * Namespace handling !!!
7933 */
7934 if (cur == NULL) {
7935 if (ctxt->context->node == NULL) return(NULL);
7936 switch (ctxt->context->node->type) {
7937 case XML_ELEMENT_NODE:
7938 case XML_TEXT_NODE:
7939 case XML_CDATA_SECTION_NODE:
7940 case XML_ENTITY_REF_NODE:
7941 case XML_ENTITY_NODE:
7942 case XML_PI_NODE:
7943 case XML_COMMENT_NODE:
7944 case XML_NOTATION_NODE:
7945 case XML_DTD_NODE:
7946 case XML_ELEMENT_DECL:
7947 case XML_ATTRIBUTE_DECL:
7948 case XML_XINCLUDE_START:
7949 case XML_XINCLUDE_END:
7950 case XML_ENTITY_DECL:
7951 if (ctxt->context->node->parent == NULL)
7952 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007953 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007954 ((ctxt->context->node->parent->name[0] == ' ') ||
7955 (xmlStrEqual(ctxt->context->node->parent->name,
7956 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007957 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007958 return(ctxt->context->node->parent);
7959 case XML_ATTRIBUTE_NODE: {
7960 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7961
7962 return(att->parent);
7963 }
7964 case XML_DOCUMENT_NODE:
7965 case XML_DOCUMENT_TYPE_NODE:
7966 case XML_DOCUMENT_FRAG_NODE:
7967 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007968#ifdef LIBXML_DOCB_ENABLED
7969 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007970#endif
7971 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007972 case XML_NAMESPACE_DECL: {
7973 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007974
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007975 if ((ns->next != NULL) &&
7976 (ns->next->type != XML_NAMESPACE_DECL))
7977 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007978 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007979 }
Owen Taylor3473f882001-02-23 17:55:21 +00007980 }
7981 }
7982 return(NULL);
7983}
7984
7985/**
7986 * xmlXPathNextAncestor:
7987 * @ctxt: the XPath Parser context
7988 * @cur: the current node in the traversal
7989 *
7990 * Traversal function for the "ancestor" direction
7991 * the ancestor axis contains the ancestors of the context node; the ancestors
7992 * of the context node consist of the parent of context node and the parent's
7993 * parent and so on; the nodes are ordered in reverse document order; thus the
7994 * parent is the first node on the axis, and the parent's parent is the second
7995 * node on the axis
7996 *
7997 * Returns the next element following that axis
7998 */
7999xmlNodePtr
8000xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008001 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008002 /*
8003 * the parent of an attribute or namespace node is the element
8004 * to which the attribute or namespace node is attached
8005 * !!!!!!!!!!!!!
8006 */
8007 if (cur == NULL) {
8008 if (ctxt->context->node == NULL) return(NULL);
8009 switch (ctxt->context->node->type) {
8010 case XML_ELEMENT_NODE:
8011 case XML_TEXT_NODE:
8012 case XML_CDATA_SECTION_NODE:
8013 case XML_ENTITY_REF_NODE:
8014 case XML_ENTITY_NODE:
8015 case XML_PI_NODE:
8016 case XML_COMMENT_NODE:
8017 case XML_DTD_NODE:
8018 case XML_ELEMENT_DECL:
8019 case XML_ATTRIBUTE_DECL:
8020 case XML_ENTITY_DECL:
8021 case XML_NOTATION_NODE:
8022 case XML_XINCLUDE_START:
8023 case XML_XINCLUDE_END:
8024 if (ctxt->context->node->parent == NULL)
8025 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008026 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008027 ((ctxt->context->node->parent->name[0] == ' ') ||
8028 (xmlStrEqual(ctxt->context->node->parent->name,
8029 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008030 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008031 return(ctxt->context->node->parent);
8032 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008033 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00008034
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008035 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00008036 }
8037 case XML_DOCUMENT_NODE:
8038 case XML_DOCUMENT_TYPE_NODE:
8039 case XML_DOCUMENT_FRAG_NODE:
8040 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008041#ifdef LIBXML_DOCB_ENABLED
8042 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008043#endif
8044 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008045 case XML_NAMESPACE_DECL: {
8046 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008047
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008048 if ((ns->next != NULL) &&
8049 (ns->next->type != XML_NAMESPACE_DECL))
8050 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008051 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008052 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008053 }
Owen Taylor3473f882001-02-23 17:55:21 +00008054 }
8055 return(NULL);
8056 }
8057 if (cur == ctxt->context->doc->children)
8058 return((xmlNodePtr) ctxt->context->doc);
8059 if (cur == (xmlNodePtr) ctxt->context->doc)
8060 return(NULL);
8061 switch (cur->type) {
8062 case XML_ELEMENT_NODE:
8063 case XML_TEXT_NODE:
8064 case XML_CDATA_SECTION_NODE:
8065 case XML_ENTITY_REF_NODE:
8066 case XML_ENTITY_NODE:
8067 case XML_PI_NODE:
8068 case XML_COMMENT_NODE:
8069 case XML_NOTATION_NODE:
8070 case XML_DTD_NODE:
8071 case XML_ELEMENT_DECL:
8072 case XML_ATTRIBUTE_DECL:
8073 case XML_ENTITY_DECL:
8074 case XML_XINCLUDE_START:
8075 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008076 if (cur->parent == NULL)
8077 return(NULL);
8078 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008079 ((cur->parent->name[0] == ' ') ||
8080 (xmlStrEqual(cur->parent->name,
8081 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008082 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008083 return(cur->parent);
8084 case XML_ATTRIBUTE_NODE: {
8085 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8086
8087 return(att->parent);
8088 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008089 case XML_NAMESPACE_DECL: {
8090 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008091
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008092 if ((ns->next != NULL) &&
8093 (ns->next->type != XML_NAMESPACE_DECL))
8094 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008095 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008096 return(NULL);
8097 }
Owen Taylor3473f882001-02-23 17:55:21 +00008098 case XML_DOCUMENT_NODE:
8099 case XML_DOCUMENT_TYPE_NODE:
8100 case XML_DOCUMENT_FRAG_NODE:
8101 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008102#ifdef LIBXML_DOCB_ENABLED
8103 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008104#endif
8105 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008106 }
8107 return(NULL);
8108}
8109
8110/**
8111 * xmlXPathNextAncestorOrSelf:
8112 * @ctxt: the XPath Parser context
8113 * @cur: the current node in the traversal
8114 *
8115 * Traversal function for the "ancestor-or-self" direction
8116 * he ancestor-or-self axis contains the context node and ancestors of
8117 * the context node in reverse document order; thus the context node is
8118 * the first node on the axis, and the context node's parent the second;
8119 * parent here is defined the same as with the parent axis.
8120 *
8121 * Returns the next element following that axis
8122 */
8123xmlNodePtr
8124xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008125 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008126 if (cur == NULL)
8127 return(ctxt->context->node);
8128 return(xmlXPathNextAncestor(ctxt, cur));
8129}
8130
8131/**
8132 * xmlXPathNextFollowingSibling:
8133 * @ctxt: the XPath Parser context
8134 * @cur: the current node in the traversal
8135 *
8136 * Traversal function for the "following-sibling" direction
8137 * The following-sibling axis contains the following siblings of the context
8138 * node in document order.
8139 *
8140 * Returns the next element following that axis
8141 */
8142xmlNodePtr
8143xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008144 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008145 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8146 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8147 return(NULL);
8148 if (cur == (xmlNodePtr) ctxt->context->doc)
8149 return(NULL);
8150 if (cur == NULL)
8151 return(ctxt->context->node->next);
8152 return(cur->next);
8153}
8154
8155/**
8156 * xmlXPathNextPrecedingSibling:
8157 * @ctxt: the XPath Parser context
8158 * @cur: the current node in the traversal
8159 *
8160 * Traversal function for the "preceding-sibling" direction
8161 * The preceding-sibling axis contains the preceding siblings of the context
8162 * node in reverse document order; the first preceding sibling is first on the
8163 * axis; the sibling preceding that node is the second on the axis and so on.
8164 *
8165 * Returns the next element following that axis
8166 */
8167xmlNodePtr
8168xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008169 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008170 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8171 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8172 return(NULL);
8173 if (cur == (xmlNodePtr) ctxt->context->doc)
8174 return(NULL);
8175 if (cur == NULL)
8176 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008177 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8178 cur = cur->prev;
8179 if (cur == NULL)
8180 return(ctxt->context->node->prev);
8181 }
Owen Taylor3473f882001-02-23 17:55:21 +00008182 return(cur->prev);
8183}
8184
8185/**
8186 * xmlXPathNextFollowing:
8187 * @ctxt: the XPath Parser context
8188 * @cur: the current node in the traversal
8189 *
8190 * Traversal function for the "following" direction
8191 * The following axis contains all nodes in the same document as the context
8192 * node that are after the context node in document order, excluding any
8193 * descendants and excluding attribute nodes and namespace nodes; the nodes
8194 * are ordered in document order
8195 *
8196 * Returns the next element following that axis
8197 */
8198xmlNodePtr
8199xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008200 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008201 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8202 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8203 return(cur->children);
8204
8205 if (cur == NULL) {
8206 cur = ctxt->context->node;
8207 if (cur->type == XML_NAMESPACE_DECL)
Daniel Veillard91d19752010-10-15 14:30:52 +02008208 return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008209 if (cur->type == XML_ATTRIBUTE_NODE)
8210 cur = cur->parent;
Daniel Veillard91d19752010-10-15 14:30:52 +02008211 }
Owen Taylor3473f882001-02-23 17:55:21 +00008212 if (cur == NULL) return(NULL) ; /* ERROR */
8213 if (cur->next != NULL) return(cur->next) ;
8214 do {
8215 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008216 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008217 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8218 if (cur->next != NULL) return(cur->next);
8219 } while (cur != NULL);
8220 return(cur);
8221}
8222
8223/*
8224 * xmlXPathIsAncestor:
8225 * @ancestor: the ancestor node
8226 * @node: the current node
8227 *
8228 * Check that @ancestor is a @node's ancestor
8229 *
8230 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8231 */
8232static int
8233xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8234 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008235 if (node->type == XML_NAMESPACE_DECL)
8236 return(0);
8237 if (ancestor->type == XML_NAMESPACE_DECL)
8238 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008239 /* nodes need to be in the same document */
8240 if (ancestor->doc != node->doc) return(0);
8241 /* avoid searching if ancestor or node is the root node */
8242 if (ancestor == (xmlNodePtr) node->doc) return(1);
8243 if (node == (xmlNodePtr) ancestor->doc) return(0);
8244 while (node->parent != NULL) {
8245 if (node->parent == ancestor)
8246 return(1);
8247 node = node->parent;
8248 }
8249 return(0);
8250}
8251
8252/**
8253 * xmlXPathNextPreceding:
8254 * @ctxt: the XPath Parser context
8255 * @cur: the current node in the traversal
8256 *
8257 * Traversal function for the "preceding" direction
8258 * the preceding axis contains all nodes in the same document as the context
8259 * node that are before the context node in document order, excluding any
8260 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8261 * ordered in reverse document order
8262 *
8263 * Returns the next element following that axis
8264 */
8265xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008266xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8267{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008268 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008269 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008270 cur = ctxt->context->node;
Daniel Veillardea90b892010-10-22 15:50:50 +02008271 if (cur->type == XML_NAMESPACE_DECL)
8272 return(NULL);
8273 if (cur->type == XML_ATTRIBUTE_NODE)
8274 return(cur->parent);
8275 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008276 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008277 return (NULL);
8278 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8279 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008280 do {
8281 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008282 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8283 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008284 }
8285
8286 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008287 if (cur == NULL)
8288 return (NULL);
8289 if (cur == ctxt->context->doc->children)
8290 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008291 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008292 return (cur);
8293}
8294
8295/**
8296 * xmlXPathNextPrecedingInternal:
8297 * @ctxt: the XPath Parser context
8298 * @cur: the current node in the traversal
8299 *
8300 * Traversal function for the "preceding" direction
8301 * the preceding axis contains all nodes in the same document as the context
8302 * node that are before the context node in document order, excluding any
8303 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8304 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008305 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008306 * state kept in the parser context: ctxt->ancestor.
8307 *
8308 * Returns the next element following that axis
8309 */
8310static xmlNodePtr
8311xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8312 xmlNodePtr cur)
8313{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008314 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008315 if (cur == NULL) {
8316 cur = ctxt->context->node;
8317 if (cur == NULL)
8318 return (NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008319 if (cur->type == XML_NAMESPACE_DECL)
8320 return (NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008321 ctxt->ancestor = cur->parent;
8322 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008323 if (cur->type == XML_NAMESPACE_DECL)
8324 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008325 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8326 cur = cur->prev;
8327 while (cur->prev == NULL) {
8328 cur = cur->parent;
8329 if (cur == NULL)
8330 return (NULL);
8331 if (cur == ctxt->context->doc->children)
8332 return (NULL);
8333 if (cur != ctxt->ancestor)
8334 return (cur);
8335 ctxt->ancestor = cur->parent;
8336 }
8337 cur = cur->prev;
8338 while (cur->last != NULL)
8339 cur = cur->last;
8340 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008341}
8342
8343/**
8344 * xmlXPathNextNamespace:
8345 * @ctxt: the XPath Parser context
8346 * @cur: the current attribute in the traversal
8347 *
8348 * Traversal function for the "namespace" direction
8349 * the namespace axis contains the namespace nodes of the context node;
8350 * the order of nodes on this axis is implementation-defined; the axis will
8351 * be empty unless the context node is an element
8352 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008353 * We keep the XML namespace node at the end of the list.
8354 *
Owen Taylor3473f882001-02-23 17:55:21 +00008355 * Returns the next element following that axis
8356 */
8357xmlNodePtr
8358xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008359 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008360 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008361 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008362 if (ctxt->context->tmpNsList != NULL)
8363 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008364 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008365 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008366 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008367 if (ctxt->context->tmpNsList != NULL) {
8368 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8369 ctxt->context->tmpNsNr++;
8370 }
8371 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008372 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008373 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008374 if (ctxt->context->tmpNsNr > 0) {
8375 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8376 } else {
8377 if (ctxt->context->tmpNsList != NULL)
8378 xmlFree(ctxt->context->tmpNsList);
8379 ctxt->context->tmpNsList = NULL;
8380 return(NULL);
8381 }
Owen Taylor3473f882001-02-23 17:55:21 +00008382}
8383
8384/**
8385 * xmlXPathNextAttribute:
8386 * @ctxt: the XPath Parser context
8387 * @cur: the current attribute in the traversal
8388 *
8389 * Traversal function for the "attribute" direction
8390 * TODO: support DTD inherited default attributes
8391 *
8392 * Returns the next element following that axis
8393 */
8394xmlNodePtr
8395xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008396 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008397 if (ctxt->context->node == NULL)
8398 return(NULL);
8399 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8400 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008401 if (cur == NULL) {
8402 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8403 return(NULL);
8404 return((xmlNodePtr)ctxt->context->node->properties);
8405 }
8406 return((xmlNodePtr)cur->next);
8407}
8408
8409/************************************************************************
8410 * *
8411 * NodeTest Functions *
8412 * *
8413 ************************************************************************/
8414
Owen Taylor3473f882001-02-23 17:55:21 +00008415#define IS_FUNCTION 200
8416
Owen Taylor3473f882001-02-23 17:55:21 +00008417
8418/************************************************************************
8419 * *
8420 * Implicit tree core function library *
8421 * *
8422 ************************************************************************/
8423
8424/**
8425 * xmlXPathRoot:
8426 * @ctxt: the XPath Parser context
8427 *
8428 * Initialize the context to the root of the document
8429 */
8430void
8431xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008432 if ((ctxt == NULL) || (ctxt->context == NULL))
8433 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008434 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008435 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8436 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008437}
8438
8439/************************************************************************
8440 * *
8441 * The explicit core function library *
8442 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8443 * *
8444 ************************************************************************/
8445
8446
8447/**
8448 * xmlXPathLastFunction:
8449 * @ctxt: the XPath Parser context
8450 * @nargs: the number of arguments
8451 *
8452 * Implement the last() XPath function
8453 * number last()
8454 * The last function returns the number of nodes in the context node list.
8455 */
8456void
8457xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8458 CHECK_ARITY(0);
8459 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008460 valuePush(ctxt,
8461 xmlXPathCacheNewFloat(ctxt->context,
8462 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008463#ifdef DEBUG_EXPR
8464 xmlGenericError(xmlGenericErrorContext,
8465 "last() : %d\n", ctxt->context->contextSize);
8466#endif
8467 } else {
8468 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8469 }
8470}
8471
8472/**
8473 * xmlXPathPositionFunction:
8474 * @ctxt: the XPath Parser context
8475 * @nargs: the number of arguments
8476 *
8477 * Implement the position() XPath function
8478 * number position()
8479 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008480 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008481 * will be equal to last().
8482 */
8483void
8484xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8485 CHECK_ARITY(0);
8486 if (ctxt->context->proximityPosition >= 0) {
8487 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008488 xmlXPathCacheNewFloat(ctxt->context,
8489 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008490#ifdef DEBUG_EXPR
8491 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8492 ctxt->context->proximityPosition);
8493#endif
8494 } else {
8495 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8496 }
8497}
8498
8499/**
8500 * xmlXPathCountFunction:
8501 * @ctxt: the XPath Parser context
8502 * @nargs: the number of arguments
8503 *
8504 * Implement the count() XPath function
8505 * number count(node-set)
8506 */
8507void
8508xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8509 xmlXPathObjectPtr cur;
8510
8511 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008512 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008513 ((ctxt->value->type != XPATH_NODESET) &&
8514 (ctxt->value->type != XPATH_XSLT_TREE)))
8515 XP_ERROR(XPATH_INVALID_TYPE);
8516 cur = valuePop(ctxt);
8517
Daniel Veillard911f49a2001-04-07 15:39:35 +00008518 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008519 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008520 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008521 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8522 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008523 } else {
8524 if ((cur->nodesetval->nodeNr != 1) ||
8525 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008526 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008527 } else {
8528 xmlNodePtr tmp;
8529 int i = 0;
8530
8531 tmp = cur->nodesetval->nodeTab[0];
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008532 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
Daniel Veillardfe703322001-08-14 12:18:09 +00008533 tmp = tmp->children;
8534 while (tmp != NULL) {
8535 tmp = tmp->next;
8536 i++;
8537 }
8538 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008539 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008540 }
8541 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008542 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008543}
8544
8545/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008546 * xmlXPathGetElementsByIds:
8547 * @doc: the document
8548 * @ids: a whitespace separated list of IDs
8549 *
8550 * Selects elements by their unique ID.
8551 *
8552 * Returns a node-set of selected elements.
8553 */
8554static xmlNodeSetPtr
8555xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8556 xmlNodeSetPtr ret;
8557 const xmlChar *cur = ids;
8558 xmlChar *ID;
8559 xmlAttrPtr attr;
8560 xmlNodePtr elem = NULL;
8561
Daniel Veillard7a985a12003-07-06 17:57:42 +00008562 if (ids == NULL) return(NULL);
8563
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008564 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008565 if (ret == NULL)
8566 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008567
William M. Brack76e95df2003-10-18 16:20:14 +00008568 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008569 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008570 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008571 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008572
8573 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008574 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008575 /*
8576 * We used to check the fact that the value passed
8577 * was an NCName, but this generated much troubles for
8578 * me and Aleksey Sanin, people blatantly violated that
8579 * constaint, like Visa3D spec.
8580 * if (xmlValidateNCName(ID, 1) == 0)
8581 */
8582 attr = xmlGetID(doc, ID);
8583 if (attr != NULL) {
8584 if (attr->type == XML_ATTRIBUTE_NODE)
8585 elem = attr->parent;
8586 else if (attr->type == XML_ELEMENT_NODE)
8587 elem = (xmlNodePtr) attr;
8588 else
8589 elem = NULL;
8590 if (elem != NULL)
8591 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008592 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008593 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008594 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008595
William M. Brack76e95df2003-10-18 16:20:14 +00008596 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008597 ids = cur;
8598 }
8599 return(ret);
8600}
8601
8602/**
Owen Taylor3473f882001-02-23 17:55:21 +00008603 * xmlXPathIdFunction:
8604 * @ctxt: the XPath Parser context
8605 * @nargs: the number of arguments
8606 *
8607 * Implement the id() XPath function
8608 * node-set id(object)
8609 * The id function selects elements by their unique ID
8610 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8611 * then the result is the union of the result of applying id to the
8612 * string value of each of the nodes in the argument node-set. When the
8613 * argument to id is of any other type, the argument is converted to a
8614 * string as if by a call to the string function; the string is split
8615 * into a whitespace-separated list of tokens (whitespace is any sequence
8616 * of characters matching the production S); the result is a node-set
8617 * containing the elements in the same document as the context node that
8618 * have a unique ID equal to any of the tokens in the list.
8619 */
8620void
8621xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008622 xmlChar *tokens;
8623 xmlNodeSetPtr ret;
8624 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008625
8626 CHECK_ARITY(1);
8627 obj = valuePop(ctxt);
8628 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008629 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008630 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008631 int i;
8632
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008633 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008634 /*
8635 * FIXME -- in an out-of-memory condition this will behave badly.
8636 * The solution is not clear -- we already popped an item from
8637 * ctxt, so the object is in a corrupt state.
8638 */
Owen Taylor3473f882001-02-23 17:55:21 +00008639
Daniel Veillard911f49a2001-04-07 15:39:35 +00008640 if (obj->nodesetval != NULL) {
8641 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008642 tokens =
8643 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8644 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8645 ret = xmlXPathNodeSetMerge(ret, ns);
8646 xmlXPathFreeNodeSet(ns);
8647 if (tokens != NULL)
8648 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008649 }
Owen Taylor3473f882001-02-23 17:55:21 +00008650 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008651 xmlXPathReleaseObject(ctxt->context, obj);
8652 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008653 return;
8654 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008655 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008656 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008657 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008658 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008659 return;
8660}
8661
8662/**
8663 * xmlXPathLocalNameFunction:
8664 * @ctxt: the XPath Parser context
8665 * @nargs: the number of arguments
8666 *
8667 * Implement the local-name() XPath function
8668 * string local-name(node-set?)
8669 * The local-name function returns a string containing the local part
8670 * of the name of the node in the argument node-set that is first in
8671 * document order. If the node-set is empty or the first node has no
8672 * name, an empty string is returned. If the argument is omitted it
8673 * defaults to the context node.
8674 */
8675void
8676xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8677 xmlXPathObjectPtr cur;
8678
Daniel Veillarda82b1822004-11-08 16:24:57 +00008679 if (ctxt == NULL) return;
8680
Owen Taylor3473f882001-02-23 17:55:21 +00008681 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008682 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8683 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008684 nargs = 1;
8685 }
8686
8687 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008688 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008689 ((ctxt->value->type != XPATH_NODESET) &&
8690 (ctxt->value->type != XPATH_XSLT_TREE)))
8691 XP_ERROR(XPATH_INVALID_TYPE);
8692 cur = valuePop(ctxt);
8693
Daniel Veillard911f49a2001-04-07 15:39:35 +00008694 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008695 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008696 } else {
8697 int i = 0; /* Should be first in document order !!!!! */
8698 switch (cur->nodesetval->nodeTab[i]->type) {
8699 case XML_ELEMENT_NODE:
8700 case XML_ATTRIBUTE_NODE:
8701 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008702 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008703 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008704 else
8705 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008706 xmlXPathCacheNewString(ctxt->context,
8707 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008708 break;
8709 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008710 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008711 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8712 break;
8713 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008714 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008715 }
8716 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008717 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008718}
8719
8720/**
8721 * xmlXPathNamespaceURIFunction:
8722 * @ctxt: the XPath Parser context
8723 * @nargs: the number of arguments
8724 *
8725 * Implement the namespace-uri() XPath function
8726 * string namespace-uri(node-set?)
8727 * The namespace-uri function returns a string containing the
8728 * namespace URI of the expanded name of the node in the argument
8729 * node-set that is first in document order. If the node-set is empty,
8730 * the first node has no name, or the expanded name has no namespace
8731 * URI, an empty string is returned. If the argument is omitted it
8732 * defaults to the context node.
8733 */
8734void
8735xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8736 xmlXPathObjectPtr cur;
8737
Daniel Veillarda82b1822004-11-08 16:24:57 +00008738 if (ctxt == NULL) return;
8739
Owen Taylor3473f882001-02-23 17:55:21 +00008740 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008741 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8742 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008743 nargs = 1;
8744 }
8745 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008746 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008747 ((ctxt->value->type != XPATH_NODESET) &&
8748 (ctxt->value->type != XPATH_XSLT_TREE)))
8749 XP_ERROR(XPATH_INVALID_TYPE);
8750 cur = valuePop(ctxt);
8751
Daniel Veillard911f49a2001-04-07 15:39:35 +00008752 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008753 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008754 } else {
8755 int i = 0; /* Should be first in document order !!!!! */
8756 switch (cur->nodesetval->nodeTab[i]->type) {
8757 case XML_ELEMENT_NODE:
8758 case XML_ATTRIBUTE_NODE:
8759 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008760 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008761 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008762 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008763 cur->nodesetval->nodeTab[i]->ns->href));
8764 break;
8765 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008766 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008767 }
8768 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008769 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008770}
8771
8772/**
8773 * xmlXPathNameFunction:
8774 * @ctxt: the XPath Parser context
8775 * @nargs: the number of arguments
8776 *
8777 * Implement the name() XPath function
8778 * string name(node-set?)
8779 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008780 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008781 * order. The QName must represent the name with respect to the namespace
8782 * declarations in effect on the node whose name is being represented.
8783 * Typically, this will be the form in which the name occurred in the XML
8784 * source. This need not be the case if there are namespace declarations
8785 * in effect on the node that associate multiple prefixes with the same
8786 * namespace. However, an implementation may include information about
8787 * the original prefix in its representation of nodes; in this case, an
8788 * implementation can ensure that the returned string is always the same
8789 * as the QName used in the XML source. If the argument it omitted it
8790 * defaults to the context node.
8791 * Libxml keep the original prefix so the "real qualified name" used is
8792 * returned.
8793 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008794static void
Daniel Veillard04383752001-07-08 14:27:15 +00008795xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8796{
Owen Taylor3473f882001-02-23 17:55:21 +00008797 xmlXPathObjectPtr cur;
8798
8799 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008800 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8801 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008802 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008803 }
8804
8805 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008806 if ((ctxt->value == NULL) ||
8807 ((ctxt->value->type != XPATH_NODESET) &&
8808 (ctxt->value->type != XPATH_XSLT_TREE)))
8809 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008810 cur = valuePop(ctxt);
8811
Daniel Veillard911f49a2001-04-07 15:39:35 +00008812 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008813 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008814 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008815 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008816
Daniel Veillard04383752001-07-08 14:27:15 +00008817 switch (cur->nodesetval->nodeTab[i]->type) {
8818 case XML_ELEMENT_NODE:
8819 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008820 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008821 valuePush(ctxt,
8822 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008823 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8824 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008825 valuePush(ctxt,
8826 xmlXPathCacheNewString(ctxt->context,
8827 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008828 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008829 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008830
Daniel Veillardc00cda82003-04-07 10:22:39 +00008831 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8832 cur->nodesetval->nodeTab[i]->ns->prefix,
8833 NULL, 0);
8834 if (fullname == cur->nodesetval->nodeTab[i]->name)
8835 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8836 if (fullname == NULL) {
8837 XP_ERROR(XPATH_MEMORY_ERROR);
8838 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008839 valuePush(ctxt, xmlXPathCacheWrapString(
8840 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008841 }
8842 break;
8843 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008844 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8845 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008846 xmlXPathLocalNameFunction(ctxt, 1);
8847 }
Owen Taylor3473f882001-02-23 17:55:21 +00008848 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008849 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008850}
8851
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008852
8853/**
Owen Taylor3473f882001-02-23 17:55:21 +00008854 * xmlXPathStringFunction:
8855 * @ctxt: the XPath Parser context
8856 * @nargs: the number of arguments
8857 *
8858 * Implement the string() XPath function
8859 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008860 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008861 * - A node-set is converted to a string by returning the value of
8862 * the node in the node-set that is first in document order.
8863 * If the node-set is empty, an empty string is returned.
8864 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008865 * + NaN is converted to the string NaN
8866 * + positive zero is converted to the string 0
8867 * + negative zero is converted to the string 0
8868 * + positive infinity is converted to the string Infinity
8869 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008870 * + if the number is an integer, the number is represented in
8871 * decimal form as a Number with no decimal point and no leading
8872 * zeros, preceded by a minus sign (-) if the number is negative
8873 * + otherwise, the number is represented in decimal form as a
8874 * Number including a decimal point with at least one digit
8875 * before the decimal point and at least one digit after the
8876 * decimal point, preceded by a minus sign (-) if the number
8877 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008878 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008879 * before the decimal point; beyond the one required digit
8880 * after the decimal point there must be as many, but only as
8881 * many, more digits as are needed to uniquely distinguish the
8882 * number from all other IEEE 754 numeric values.
8883 * - The boolean false value is converted to the string false.
8884 * The boolean true value is converted to the string true.
8885 *
8886 * If the argument is omitted, it defaults to a node-set with the
8887 * context node as its only member.
8888 */
8889void
8890xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8891 xmlXPathObjectPtr cur;
8892
Daniel Veillarda82b1822004-11-08 16:24:57 +00008893 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008894 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008895 valuePush(ctxt,
8896 xmlXPathCacheWrapString(ctxt->context,
8897 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008898 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008899 }
8900
8901 CHECK_ARITY(1);
8902 cur = valuePop(ctxt);
8903 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008904 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008905}
8906
8907/**
8908 * xmlXPathStringLengthFunction:
8909 * @ctxt: the XPath Parser context
8910 * @nargs: the number of arguments
8911 *
8912 * Implement the string-length() XPath function
8913 * number string-length(string?)
8914 * The string-length returns the number of characters in the string
8915 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8916 * the context node converted to a string, in other words the value
8917 * of the context node.
8918 */
8919void
8920xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8921 xmlXPathObjectPtr cur;
8922
8923 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008924 if ((ctxt == NULL) || (ctxt->context == NULL))
8925 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008926 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008927 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008928 } else {
8929 xmlChar *content;
8930
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008931 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008932 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8933 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008934 xmlFree(content);
8935 }
8936 return;
8937 }
8938 CHECK_ARITY(1);
8939 CAST_TO_STRING;
8940 CHECK_TYPE(XPATH_STRING);
8941 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008942 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008943 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008944 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008945}
8946
8947/**
8948 * xmlXPathConcatFunction:
8949 * @ctxt: the XPath Parser context
8950 * @nargs: the number of arguments
8951 *
8952 * Implement the concat() XPath function
8953 * string concat(string, string, string*)
8954 * The concat function returns the concatenation of its arguments.
8955 */
8956void
8957xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8958 xmlXPathObjectPtr cur, newobj;
8959 xmlChar *tmp;
8960
Daniel Veillarda82b1822004-11-08 16:24:57 +00008961 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008962 if (nargs < 2) {
8963 CHECK_ARITY(2);
8964 }
8965
8966 CAST_TO_STRING;
8967 cur = valuePop(ctxt);
8968 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008969 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008970 return;
8971 }
8972 nargs--;
8973
8974 while (nargs > 0) {
8975 CAST_TO_STRING;
8976 newobj = valuePop(ctxt);
8977 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008978 xmlXPathReleaseObject(ctxt->context, newobj);
8979 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008980 XP_ERROR(XPATH_INVALID_TYPE);
8981 }
8982 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8983 newobj->stringval = cur->stringval;
8984 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008985 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008986 nargs--;
8987 }
8988 valuePush(ctxt, cur);
8989}
8990
8991/**
8992 * xmlXPathContainsFunction:
8993 * @ctxt: the XPath Parser context
8994 * @nargs: the number of arguments
8995 *
8996 * Implement the contains() XPath function
8997 * boolean contains(string, string)
8998 * The contains function returns true if the first argument string
8999 * contains the second argument string, and otherwise returns false.
9000 */
9001void
9002xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9003 xmlXPathObjectPtr hay, needle;
9004
9005 CHECK_ARITY(2);
9006 CAST_TO_STRING;
9007 CHECK_TYPE(XPATH_STRING);
9008 needle = valuePop(ctxt);
9009 CAST_TO_STRING;
9010 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009011
Owen Taylor3473f882001-02-23 17:55:21 +00009012 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009013 xmlXPathReleaseObject(ctxt->context, hay);
9014 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009015 XP_ERROR(XPATH_INVALID_TYPE);
9016 }
9017 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009018 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009019 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009020 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9021 xmlXPathReleaseObject(ctxt->context, hay);
9022 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009023}
9024
9025/**
9026 * xmlXPathStartsWithFunction:
9027 * @ctxt: the XPath Parser context
9028 * @nargs: the number of arguments
9029 *
9030 * Implement the starts-with() XPath function
9031 * boolean starts-with(string, string)
9032 * The starts-with function returns true if the first argument string
9033 * starts with the second argument string, and otherwise returns false.
9034 */
9035void
9036xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9037 xmlXPathObjectPtr hay, needle;
9038 int n;
9039
9040 CHECK_ARITY(2);
9041 CAST_TO_STRING;
9042 CHECK_TYPE(XPATH_STRING);
9043 needle = valuePop(ctxt);
9044 CAST_TO_STRING;
9045 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009046
Owen Taylor3473f882001-02-23 17:55:21 +00009047 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009048 xmlXPathReleaseObject(ctxt->context, hay);
9049 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009050 XP_ERROR(XPATH_INVALID_TYPE);
9051 }
9052 n = xmlStrlen(needle->stringval);
9053 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009054 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009055 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009056 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9057 xmlXPathReleaseObject(ctxt->context, hay);
9058 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009059}
9060
9061/**
9062 * xmlXPathSubstringFunction:
9063 * @ctxt: the XPath Parser context
9064 * @nargs: the number of arguments
9065 *
9066 * Implement the substring() XPath function
9067 * string substring(string, number, number?)
9068 * The substring function returns the substring of the first argument
9069 * starting at the position specified in the second argument with
9070 * length specified in the third argument. For example,
9071 * substring("12345",2,3) returns "234". If the third argument is not
9072 * specified, it returns the substring starting at the position specified
9073 * in the second argument and continuing to the end of the string. For
9074 * example, substring("12345",2) returns "2345". More precisely, each
9075 * character in the string (see [3.6 Strings]) is considered to have a
9076 * numeric position: the position of the first character is 1, the position
9077 * of the second character is 2 and so on. The returned substring contains
9078 * those characters for which the position of the character is greater than
9079 * or equal to the second argument and, if the third argument is specified,
9080 * less than the sum of the second and third arguments; the comparisons
9081 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009082 * - substring("12345", 1.5, 2.6) returns "234"
9083 * - substring("12345", 0, 3) returns "12"
9084 * - substring("12345", 0 div 0, 3) returns ""
9085 * - substring("12345", 1, 0 div 0) returns ""
9086 * - substring("12345", -42, 1 div 0) returns "12345"
9087 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009088 */
9089void
9090xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9091 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009092 double le=0, in;
9093 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009094 xmlChar *ret;
9095
Owen Taylor3473f882001-02-23 17:55:21 +00009096 if (nargs < 2) {
9097 CHECK_ARITY(2);
9098 }
9099 if (nargs > 3) {
9100 CHECK_ARITY(3);
9101 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009102 /*
9103 * take care of possible last (position) argument
9104 */
Owen Taylor3473f882001-02-23 17:55:21 +00009105 if (nargs == 3) {
9106 CAST_TO_NUMBER;
9107 CHECK_TYPE(XPATH_NUMBER);
9108 len = valuePop(ctxt);
9109 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009110 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009111 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009112
Owen Taylor3473f882001-02-23 17:55:21 +00009113 CAST_TO_NUMBER;
9114 CHECK_TYPE(XPATH_NUMBER);
9115 start = valuePop(ctxt);
9116 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009117 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009118 CAST_TO_STRING;
9119 CHECK_TYPE(XPATH_STRING);
9120 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009121 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009122
Daniel Veillard97ac1312001-05-30 19:14:17 +00009123 /*
9124 * If last pos not present, calculate last position
9125 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009126 if (nargs != 3) {
9127 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009128 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009129 in = 1.0;
9130 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009131
Daniel Veillard45490ae2008-07-29 09:13:19 +00009132 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009133 * the index is NaN, the length is NaN, or both
9134 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009135 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009136 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009137 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009138 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009139 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009140 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009141 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009142 * First we go to integer form, rounding up
9143 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009144 */
9145 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009146 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009147
Daniel Veillard9e412302002-06-10 15:59:44 +00009148 if (xmlXPathIsInf(le) == 1) {
9149 l = m;
9150 if (i < 1)
9151 i = 1;
9152 }
9153 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9154 l = 0;
9155 else {
9156 l = (int) le;
9157 if (((double)l)+0.5 <= le) l++;
9158 }
9159
9160 /* Now we normalize inidices */
9161 i -= 1;
9162 l += i;
9163 if (i < 0)
9164 i = 0;
9165 if (l > m)
9166 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009167
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009168 /* number of chars to copy */
9169 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009170
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009171 ret = xmlUTF8Strsub(str->stringval, i, l);
9172 }
9173 else {
9174 ret = NULL;
9175 }
Owen Taylor3473f882001-02-23 17:55:21 +00009176 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009177 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009178 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009179 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009180 xmlFree(ret);
9181 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009182 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009183}
9184
9185/**
9186 * xmlXPathSubstringBeforeFunction:
9187 * @ctxt: the XPath Parser context
9188 * @nargs: the number of arguments
9189 *
9190 * Implement the substring-before() XPath function
9191 * string substring-before(string, string)
9192 * The substring-before function returns the substring of the first
9193 * argument string that precedes the first occurrence of the second
9194 * argument string in the first argument string, or the empty string
9195 * if the first argument string does not contain the second argument
9196 * string. For example, substring-before("1999/04/01","/") returns 1999.
9197 */
9198void
9199xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9200 xmlXPathObjectPtr str;
9201 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009202 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009203 const xmlChar *point;
9204 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009205
Owen Taylor3473f882001-02-23 17:55:21 +00009206 CHECK_ARITY(2);
9207 CAST_TO_STRING;
9208 find = valuePop(ctxt);
9209 CAST_TO_STRING;
9210 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009211
Daniel Veillardade10f22012-07-12 09:43:27 +08009212 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009213 if (target) {
9214 point = xmlStrstr(str->stringval, find->stringval);
9215 if (point) {
9216 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009217 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009218 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009219 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009220 xmlBufContent(target)));
9221 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009222 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009223 xmlXPathReleaseObject(ctxt->context, str);
9224 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009225}
9226
9227/**
9228 * xmlXPathSubstringAfterFunction:
9229 * @ctxt: the XPath Parser context
9230 * @nargs: the number of arguments
9231 *
9232 * Implement the substring-after() XPath function
9233 * string substring-after(string, string)
9234 * The substring-after function returns the substring of the first
9235 * argument string that follows the first occurrence of the second
9236 * argument string in the first argument string, or the empty stringi
9237 * if the first argument string does not contain the second argument
9238 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9239 * and substring-after("1999/04/01","19") returns 99/04/01.
9240 */
9241void
9242xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9243 xmlXPathObjectPtr str;
9244 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009245 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009246 const xmlChar *point;
9247 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009248
Owen Taylor3473f882001-02-23 17:55:21 +00009249 CHECK_ARITY(2);
9250 CAST_TO_STRING;
9251 find = valuePop(ctxt);
9252 CAST_TO_STRING;
9253 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009254
Daniel Veillardade10f22012-07-12 09:43:27 +08009255 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009256 if (target) {
9257 point = xmlStrstr(str->stringval, find->stringval);
9258 if (point) {
9259 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009260 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009261 xmlStrlen(str->stringval) - offset);
9262 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009263 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009264 xmlBufContent(target)));
9265 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009266 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009267 xmlXPathReleaseObject(ctxt->context, str);
9268 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009269}
9270
9271/**
9272 * xmlXPathNormalizeFunction:
9273 * @ctxt: the XPath Parser context
9274 * @nargs: the number of arguments
9275 *
9276 * Implement the normalize-space() XPath function
9277 * string normalize-space(string?)
9278 * The normalize-space function returns the argument string with white
9279 * space normalized by stripping leading and trailing whitespace
9280 * and replacing sequences of whitespace characters by a single
9281 * space. Whitespace characters are the same allowed by the S production
9282 * in XML. If the argument is omitted, it defaults to the context
9283 * node converted to a string, in other words the value of the context node.
9284 */
9285void
9286xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9287 xmlXPathObjectPtr obj = NULL;
9288 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009289 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009290 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009291
Daniel Veillarda82b1822004-11-08 16:24:57 +00009292 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009293 if (nargs == 0) {
9294 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009295 valuePush(ctxt,
9296 xmlXPathCacheWrapString(ctxt->context,
9297 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009298 nargs = 1;
9299 }
9300
9301 CHECK_ARITY(1);
9302 CAST_TO_STRING;
9303 CHECK_TYPE(XPATH_STRING);
9304 obj = valuePop(ctxt);
9305 source = obj->stringval;
9306
Daniel Veillardade10f22012-07-12 09:43:27 +08009307 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009308 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009309
Owen Taylor3473f882001-02-23 17:55:21 +00009310 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009311 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009312 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009313
Owen Taylor3473f882001-02-23 17:55:21 +00009314 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9315 blank = 0;
9316 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009317 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009318 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009319 } else {
9320 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009321 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009322 blank = 0;
9323 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009324 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009325 }
9326 source++;
9327 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009328 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009329 xmlBufContent(target)));
9330 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009331 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009332 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009333}
9334
9335/**
9336 * xmlXPathTranslateFunction:
9337 * @ctxt: the XPath Parser context
9338 * @nargs: the number of arguments
9339 *
9340 * Implement the translate() XPath function
9341 * string translate(string, string, string)
9342 * The translate function returns the first argument string with
9343 * occurrences of characters in the second argument string replaced
9344 * by the character at the corresponding position in the third argument
9345 * string. For example, translate("bar","abc","ABC") returns the string
9346 * BAr. If there is a character in the second argument string with no
9347 * character at a corresponding position in the third argument string
9348 * (because the second argument string is longer than the third argument
9349 * string), then occurrences of that character in the first argument
9350 * string are removed. For example, translate("--aaa--","abc-","ABC")
9351 * returns "AAA". If a character occurs more than once in second
9352 * argument string, then the first occurrence determines the replacement
9353 * character. If the third argument string is longer than the second
9354 * argument string, then excess characters are ignored.
9355 */
9356void
9357xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009358 xmlXPathObjectPtr str;
9359 xmlXPathObjectPtr from;
9360 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009361 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009362 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009363 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009364 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009365 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009366
Daniel Veillarde043ee12001-04-16 14:08:07 +00009367 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009368
Daniel Veillarde043ee12001-04-16 14:08:07 +00009369 CAST_TO_STRING;
9370 to = valuePop(ctxt);
9371 CAST_TO_STRING;
9372 from = valuePop(ctxt);
9373 CAST_TO_STRING;
9374 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009375
Daniel Veillardade10f22012-07-12 09:43:27 +08009376 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009377 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009378 max = xmlUTF8Strlen(to->stringval);
9379 for (cptr = str->stringval; (ch=*cptr); ) {
9380 offset = xmlUTF8Strloc(from->stringval, cptr);
9381 if (offset >= 0) {
9382 if (offset < max) {
9383 point = xmlUTF8Strpos(to->stringval, offset);
9384 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009385 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009386 }
9387 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009388 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009389
9390 /* Step to next character in input */
9391 cptr++;
9392 if ( ch & 0x80 ) {
9393 /* if not simple ascii, verify proper format */
9394 if ( (ch & 0xc0) != 0xc0 ) {
9395 xmlGenericError(xmlGenericErrorContext,
9396 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009397 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009398 break;
9399 }
9400 /* then skip over remaining bytes for this char */
9401 while ( (ch <<= 1) & 0x80 )
9402 if ( (*cptr++ & 0xc0) != 0x80 ) {
9403 xmlGenericError(xmlGenericErrorContext,
9404 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009405 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009406 break;
9407 }
9408 if (ch & 0x80) /* must have had error encountered */
9409 break;
9410 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009411 }
Owen Taylor3473f882001-02-23 17:55:21 +00009412 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009413 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009414 xmlBufContent(target)));
9415 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009416 xmlXPathReleaseObject(ctxt->context, str);
9417 xmlXPathReleaseObject(ctxt->context, from);
9418 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009419}
9420
9421/**
9422 * xmlXPathBooleanFunction:
9423 * @ctxt: the XPath Parser context
9424 * @nargs: the number of arguments
9425 *
9426 * Implement the boolean() XPath function
9427 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009428 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009429 * - a number is true if and only if it is neither positive or
9430 * negative zero nor NaN
9431 * - a node-set is true if and only if it is non-empty
9432 * - a string is true if and only if its length is non-zero
9433 */
9434void
9435xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9436 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009437
9438 CHECK_ARITY(1);
9439 cur = valuePop(ctxt);
9440 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009441 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009442 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009443}
9444
9445/**
9446 * xmlXPathNotFunction:
9447 * @ctxt: the XPath Parser context
9448 * @nargs: the number of arguments
9449 *
9450 * Implement the not() XPath function
9451 * boolean not(boolean)
9452 * The not function returns true if its argument is false,
9453 * and false otherwise.
9454 */
9455void
9456xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9457 CHECK_ARITY(1);
9458 CAST_TO_BOOLEAN;
9459 CHECK_TYPE(XPATH_BOOLEAN);
9460 ctxt->value->boolval = ! ctxt->value->boolval;
9461}
9462
9463/**
9464 * xmlXPathTrueFunction:
9465 * @ctxt: the XPath Parser context
9466 * @nargs: the number of arguments
9467 *
9468 * Implement the true() XPath function
9469 * boolean true()
9470 */
9471void
9472xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9473 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009474 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009475}
9476
9477/**
9478 * xmlXPathFalseFunction:
9479 * @ctxt: the XPath Parser context
9480 * @nargs: the number of arguments
9481 *
9482 * Implement the false() XPath function
9483 * boolean false()
9484 */
9485void
9486xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9487 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009488 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009489}
9490
9491/**
9492 * xmlXPathLangFunction:
9493 * @ctxt: the XPath Parser context
9494 * @nargs: the number of arguments
9495 *
9496 * Implement the lang() XPath function
9497 * boolean lang(string)
9498 * The lang function returns true or false depending on whether the
9499 * language of the context node as specified by xml:lang attributes
9500 * is the same as or is a sublanguage of the language specified by
9501 * the argument string. The language of the context node is determined
9502 * by the value of the xml:lang attribute on the context node, or, if
9503 * the context node has no xml:lang attribute, by the value of the
9504 * xml:lang attribute on the nearest ancestor of the context node that
9505 * has an xml:lang attribute. If there is no such attribute, then lang
9506 * returns false. If there is such an attribute, then lang returns
9507 * true if the attribute value is equal to the argument ignoring case,
9508 * or if there is some suffix starting with - such that the attribute
9509 * value is equal to the argument ignoring that suffix of the attribute
9510 * value and ignoring case.
9511 */
9512void
9513xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009514 xmlXPathObjectPtr val = NULL;
9515 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009516 const xmlChar *lang;
9517 int ret = 0;
9518 int i;
9519
9520 CHECK_ARITY(1);
9521 CAST_TO_STRING;
9522 CHECK_TYPE(XPATH_STRING);
9523 val = valuePop(ctxt);
9524 lang = val->stringval;
9525 theLang = xmlNodeGetLang(ctxt->context->node);
9526 if ((theLang != NULL) && (lang != NULL)) {
9527 for (i = 0;lang[i] != 0;i++)
9528 if (toupper(lang[i]) != toupper(theLang[i]))
9529 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009530 if ((theLang[i] == 0) || (theLang[i] == '-'))
9531 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009532 }
9533not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009534 if (theLang != NULL)
9535 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009536
9537 xmlXPathReleaseObject(ctxt->context, val);
9538 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009539}
9540
9541/**
9542 * xmlXPathNumberFunction:
9543 * @ctxt: the XPath Parser context
9544 * @nargs: the number of arguments
9545 *
9546 * Implement the number() XPath function
9547 * number number(object?)
9548 */
9549void
9550xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9551 xmlXPathObjectPtr cur;
9552 double res;
9553
Daniel Veillarda82b1822004-11-08 16:24:57 +00009554 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009555 if (nargs == 0) {
9556 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009557 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009558 } else {
9559 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9560
9561 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009562 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009563 xmlFree(content);
9564 }
9565 return;
9566 }
9567
9568 CHECK_ARITY(1);
9569 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009570 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009571}
9572
9573/**
9574 * xmlXPathSumFunction:
9575 * @ctxt: the XPath Parser context
9576 * @nargs: the number of arguments
9577 *
9578 * Implement the sum() XPath function
9579 * number sum(node-set)
9580 * The sum function returns the sum of the values of the nodes in
9581 * the argument node-set.
9582 */
9583void
9584xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9585 xmlXPathObjectPtr cur;
9586 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009587 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009588
9589 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009590 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009591 ((ctxt->value->type != XPATH_NODESET) &&
9592 (ctxt->value->type != XPATH_XSLT_TREE)))
9593 XP_ERROR(XPATH_INVALID_TYPE);
9594 cur = valuePop(ctxt);
9595
William M. Brack08171912003-12-29 02:52:11 +00009596 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009597 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9598 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009599 }
9600 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009601 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9602 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009603}
9604
William M. Brack3d426662005-04-19 14:40:28 +00009605/*
9606 * To assure working code on multiple platforms, we want to only depend
9607 * upon the characteristic truncation of converting a floating point value
9608 * to an integer. Unfortunately, because of the different storage sizes
9609 * of our internal floating point value (double) and integer (int), we
9610 * can't directly convert (see bug 301162). This macro is a messy
9611 * 'workaround'
9612 */
9613#define XTRUNC(f, v) \
9614 f = fmod((v), INT_MAX); \
9615 f = (v) - (f) + (double)((int)(f));
9616
Owen Taylor3473f882001-02-23 17:55:21 +00009617/**
9618 * xmlXPathFloorFunction:
9619 * @ctxt: the XPath Parser context
9620 * @nargs: the number of arguments
9621 *
9622 * Implement the floor() XPath function
9623 * number floor(number)
9624 * The floor function returns the largest (closest to positive infinity)
9625 * number that is not greater than the argument and that is an integer.
9626 */
9627void
9628xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009629 double f;
9630
Owen Taylor3473f882001-02-23 17:55:21 +00009631 CHECK_ARITY(1);
9632 CAST_TO_NUMBER;
9633 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009634
William M. Brack3d426662005-04-19 14:40:28 +00009635 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009636 if (f != ctxt->value->floatval) {
9637 if (ctxt->value->floatval > 0)
9638 ctxt->value->floatval = f;
9639 else
9640 ctxt->value->floatval = f - 1;
9641 }
Owen Taylor3473f882001-02-23 17:55:21 +00009642}
9643
9644/**
9645 * xmlXPathCeilingFunction:
9646 * @ctxt: the XPath Parser context
9647 * @nargs: the number of arguments
9648 *
9649 * Implement the ceiling() XPath function
9650 * number ceiling(number)
9651 * The ceiling function returns the smallest (closest to negative infinity)
9652 * number that is not less than the argument and that is an integer.
9653 */
9654void
9655xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9656 double f;
9657
9658 CHECK_ARITY(1);
9659 CAST_TO_NUMBER;
9660 CHECK_TYPE(XPATH_NUMBER);
9661
9662#if 0
9663 ctxt->value->floatval = ceil(ctxt->value->floatval);
9664#else
William M. Brack3d426662005-04-19 14:40:28 +00009665 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009666 if (f != ctxt->value->floatval) {
9667 if (ctxt->value->floatval > 0)
9668 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009669 else {
9670 if (ctxt->value->floatval < 0 && f == 0)
9671 ctxt->value->floatval = xmlXPathNZERO;
9672 else
9673 ctxt->value->floatval = f;
9674 }
9675
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009676 }
Owen Taylor3473f882001-02-23 17:55:21 +00009677#endif
9678}
9679
9680/**
9681 * xmlXPathRoundFunction:
9682 * @ctxt: the XPath Parser context
9683 * @nargs: the number of arguments
9684 *
9685 * Implement the round() XPath function
9686 * number round(number)
9687 * The round function returns the number that is closest to the
9688 * argument and that is an integer. If there are two such numbers,
9689 * then the one that is even is returned.
9690 */
9691void
9692xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9693 double f;
9694
9695 CHECK_ARITY(1);
9696 CAST_TO_NUMBER;
9697 CHECK_TYPE(XPATH_NUMBER);
9698
Daniel Veillardcda96922001-08-21 10:56:31 +00009699 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9700 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9701 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009702 (ctxt->value->floatval == 0.0))
9703 return;
9704
William M. Brack3d426662005-04-19 14:40:28 +00009705 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009706 if (ctxt->value->floatval < 0) {
9707 if (ctxt->value->floatval < f - 0.5)
9708 ctxt->value->floatval = f - 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009709 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009710 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009711 if (ctxt->value->floatval == 0)
9712 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009713 } else {
9714 if (ctxt->value->floatval < f + 0.5)
9715 ctxt->value->floatval = f;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009716 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009717 ctxt->value->floatval = f + 1;
9718 }
Owen Taylor3473f882001-02-23 17:55:21 +00009719}
9720
9721/************************************************************************
9722 * *
9723 * The Parser *
9724 * *
9725 ************************************************************************/
9726
9727/*
William M. Brack08171912003-12-29 02:52:11 +00009728 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009729 * implementation.
9730 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009731static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009732static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009733static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009734static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009735static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9736 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009737
9738/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009739 * xmlXPathCurrentChar:
9740 * @ctxt: the XPath parser context
9741 * @cur: pointer to the beginning of the char
9742 * @len: pointer to the length of the char read
9743 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009744 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009745 * bytes in the input buffer.
9746 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009747 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009748 */
9749
9750static int
9751xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9752 unsigned char c;
9753 unsigned int val;
9754 const xmlChar *cur;
9755
9756 if (ctxt == NULL)
9757 return(0);
9758 cur = ctxt->cur;
9759
9760 /*
9761 * We are supposed to handle UTF8, check it's valid
9762 * From rfc2044: encoding of the Unicode values on UTF-8:
9763 *
9764 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9765 * 0000 0000-0000 007F 0xxxxxxx
9766 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009767 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009768 *
9769 * Check for the 0x110000 limit too
9770 */
9771 c = *cur;
9772 if (c & 0x80) {
9773 if ((cur[1] & 0xc0) != 0x80)
9774 goto encoding_error;
9775 if ((c & 0xe0) == 0xe0) {
9776
9777 if ((cur[2] & 0xc0) != 0x80)
9778 goto encoding_error;
9779 if ((c & 0xf0) == 0xf0) {
9780 if (((c & 0xf8) != 0xf0) ||
9781 ((cur[3] & 0xc0) != 0x80))
9782 goto encoding_error;
9783 /* 4-byte code */
9784 *len = 4;
9785 val = (cur[0] & 0x7) << 18;
9786 val |= (cur[1] & 0x3f) << 12;
9787 val |= (cur[2] & 0x3f) << 6;
9788 val |= cur[3] & 0x3f;
9789 } else {
9790 /* 3-byte code */
9791 *len = 3;
9792 val = (cur[0] & 0xf) << 12;
9793 val |= (cur[1] & 0x3f) << 6;
9794 val |= cur[2] & 0x3f;
9795 }
9796 } else {
9797 /* 2-byte code */
9798 *len = 2;
9799 val = (cur[0] & 0x1f) << 6;
9800 val |= cur[1] & 0x3f;
9801 }
9802 if (!IS_CHAR(val)) {
9803 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009804 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009805 return(val);
9806 } else {
9807 /* 1-byte code */
9808 *len = 1;
9809 return((int) *cur);
9810 }
9811encoding_error:
9812 /*
William M. Brack08171912003-12-29 02:52:11 +00009813 * If we detect an UTF8 error that probably means that the
9814 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009815 * declaration header. Report the error and switch the encoding
9816 * to ISO-Latin-1 (if you don't like this policy, just declare the
9817 * encoding !)
9818 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009819 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009820 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009821}
9822
9823/**
Owen Taylor3473f882001-02-23 17:55:21 +00009824 * xmlXPathParseNCName:
9825 * @ctxt: the XPath Parser context
9826 *
9827 * parse an XML namespace non qualified name.
9828 *
9829 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9830 *
9831 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9832 * CombiningChar | Extender
9833 *
9834 * Returns the namespace name or NULL
9835 */
9836
9837xmlChar *
9838xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009839 const xmlChar *in;
9840 xmlChar *ret;
9841 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009842
Daniel Veillarda82b1822004-11-08 16:24:57 +00009843 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009844 /*
9845 * Accelerator for simple ASCII names
9846 */
9847 in = ctxt->cur;
9848 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9849 ((*in >= 0x41) && (*in <= 0x5A)) ||
9850 (*in == '_')) {
9851 in++;
9852 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9853 ((*in >= 0x41) && (*in <= 0x5A)) ||
9854 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009855 (*in == '_') || (*in == '.') ||
9856 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009857 in++;
9858 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9859 (*in == '[') || (*in == ']') || (*in == ':') ||
9860 (*in == '@') || (*in == '*')) {
9861 count = in - ctxt->cur;
9862 if (count == 0)
9863 return(NULL);
9864 ret = xmlStrndup(ctxt->cur, count);
9865 ctxt->cur = in;
9866 return(ret);
9867 }
9868 }
9869 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009870}
9871
Daniel Veillard2156a562001-04-28 12:24:34 +00009872
Owen Taylor3473f882001-02-23 17:55:21 +00009873/**
9874 * xmlXPathParseQName:
9875 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009876 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009877 *
9878 * parse an XML qualified name
9879 *
9880 * [NS 5] QName ::= (Prefix ':')? LocalPart
9881 *
9882 * [NS 6] Prefix ::= NCName
9883 *
9884 * [NS 7] LocalPart ::= NCName
9885 *
9886 * Returns the function returns the local part, and prefix is updated
9887 * to get the Prefix if any.
9888 */
9889
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009890static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009891xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9892 xmlChar *ret = NULL;
9893
9894 *prefix = NULL;
9895 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009896 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009897 *prefix = ret;
9898 NEXT;
9899 ret = xmlXPathParseNCName(ctxt);
9900 }
9901 return(ret);
9902}
9903
9904/**
9905 * xmlXPathParseName:
9906 * @ctxt: the XPath Parser context
9907 *
9908 * parse an XML name
9909 *
9910 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9911 * CombiningChar | Extender
9912 *
9913 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9914 *
9915 * Returns the namespace name or NULL
9916 */
9917
9918xmlChar *
9919xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009920 const xmlChar *in;
9921 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009922 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009923
Daniel Veillarda82b1822004-11-08 16:24:57 +00009924 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009925 /*
9926 * Accelerator for simple ASCII names
9927 */
9928 in = ctxt->cur;
9929 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9930 ((*in >= 0x41) && (*in <= 0x5A)) ||
9931 (*in == '_') || (*in == ':')) {
9932 in++;
9933 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9934 ((*in >= 0x41) && (*in <= 0x5A)) ||
9935 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009936 (*in == '_') || (*in == '-') ||
9937 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009938 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009939 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009940 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009941 if (count > XML_MAX_NAME_LENGTH) {
9942 ctxt->cur = in;
9943 XP_ERRORNULL(XPATH_EXPR_ERROR);
9944 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009945 ret = xmlStrndup(ctxt->cur, count);
9946 ctxt->cur = in;
9947 return(ret);
9948 }
9949 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009950 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009951}
9952
Daniel Veillard61d80a22001-04-27 17:13:01 +00009953static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009954xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009955 xmlChar buf[XML_MAX_NAMELEN + 5];
9956 int len = 0, l;
9957 int c;
9958
9959 /*
9960 * Handler for more complex cases
9961 */
9962 c = CUR_CHAR(l);
9963 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009964 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9965 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009966 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009967 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009968 return(NULL);
9969 }
9970
9971 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9972 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9973 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009974 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009975 (IS_COMBINING(c)) ||
9976 (IS_EXTENDER(c)))) {
9977 COPY_BUF(l,buf,len,c);
9978 NEXTL(l);
9979 c = CUR_CHAR(l);
9980 if (len >= XML_MAX_NAMELEN) {
9981 /*
9982 * Okay someone managed to make a huge name, so he's ready to pay
9983 * for the processing speed.
9984 */
9985 xmlChar *buffer;
9986 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009987
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009988 if (len > XML_MAX_NAME_LENGTH) {
9989 XP_ERRORNULL(XPATH_EXPR_ERROR);
9990 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009991 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009992 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009993 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009994 }
9995 memcpy(buffer, buf, len);
9996 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9997 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009998 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009999 (IS_COMBINING(c)) ||
10000 (IS_EXTENDER(c))) {
10001 if (len + 10 > max) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010002 if (max > XML_MAX_NAME_LENGTH) {
10003 XP_ERRORNULL(XPATH_EXPR_ERROR);
10004 }
Daniel Veillard61d80a22001-04-27 17:13:01 +000010005 max *= 2;
10006 buffer = (xmlChar *) xmlRealloc(buffer,
10007 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010008 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010009 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010010 }
10011 }
10012 COPY_BUF(l,buffer,len,c);
10013 NEXTL(l);
10014 c = CUR_CHAR(l);
10015 }
10016 buffer[len] = 0;
10017 return(buffer);
10018 }
10019 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010020 if (len == 0)
10021 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010022 return(xmlStrndup(buf, len));
10023}
Daniel Veillard3cd72402002-05-13 10:33:30 +000010024
10025#define MAX_FRAC 20
10026
William M. Brack372a4452004-02-17 13:09:23 +000010027/*
10028 * These are used as divisors for the fractional part of a number.
10029 * Since the table includes 1.0 (representing '0' fractional digits),
10030 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10031 */
10032static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010033 1.0, 10.0, 100.0, 1000.0, 10000.0,
10034 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10035 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10036 100000000000000.0,
10037 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +000010038 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +000010039};
10040
Owen Taylor3473f882001-02-23 17:55:21 +000010041/**
10042 * xmlXPathStringEvalNumber:
10043 * @str: A string to scan
10044 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000010045 * [30a] Float ::= Number ('e' Digits?)?
10046 *
Owen Taylor3473f882001-02-23 17:55:21 +000010047 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010048 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010049 * [31] Digits ::= [0-9]+
10050 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010051 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +000010052 * In complement of the Number expression, this function also handles
10053 * negative values : '-' Number.
10054 *
10055 * Returns the double value.
10056 */
10057double
10058xmlXPathStringEvalNumber(const xmlChar *str) {
10059 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +000010060 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010061 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010062 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010063 int exponent = 0;
10064 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010065#ifdef __GNUC__
10066 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010067 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010068#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010069 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +000010070 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010071 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10072 return(xmlXPathNAN);
10073 }
10074 if (*cur == '-') {
10075 isneg = 1;
10076 cur++;
10077 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010078
10079#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010080 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010081 * tmp/temp is a workaround against a gcc compiler bug
10082 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010083 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010084 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010085 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010086 ret = ret * 10;
10087 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010088 ok = 1;
10089 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010090 temp = (double) tmp;
10091 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010092 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010093#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010094 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010095 while ((*cur >= '0') && (*cur <= '9')) {
10096 ret = ret * 10 + (*cur - '0');
10097 ok = 1;
10098 cur++;
10099 }
10100#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010101
Owen Taylor3473f882001-02-23 17:55:21 +000010102 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010103 int v, frac = 0;
10104 double fraction = 0;
10105
Owen Taylor3473f882001-02-23 17:55:21 +000010106 cur++;
10107 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10108 return(xmlXPathNAN);
10109 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010110 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10111 v = (*cur - '0');
10112 fraction = fraction * 10 + v;
10113 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010114 cur++;
10115 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010116 fraction /= my_pow10[frac];
10117 ret = ret + fraction;
10118 while ((*cur >= '0') && (*cur <= '9'))
10119 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010120 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010121 if ((*cur == 'e') || (*cur == 'E')) {
10122 cur++;
10123 if (*cur == '-') {
10124 is_exponent_negative = 1;
10125 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010126 } else if (*cur == '+') {
10127 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010128 }
10129 while ((*cur >= '0') && (*cur <= '9')) {
10130 exponent = exponent * 10 + (*cur - '0');
10131 cur++;
10132 }
10133 }
William M. Brack76e95df2003-10-18 16:20:14 +000010134 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010135 if (*cur != 0) return(xmlXPathNAN);
10136 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010137 if (is_exponent_negative) exponent = -exponent;
10138 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010139 return(ret);
10140}
10141
10142/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010143 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010144 * @ctxt: the XPath Parser context
10145 *
10146 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010147 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010148 * [31] Digits ::= [0-9]+
10149 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010150 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010151 *
10152 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010153static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010154xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10155{
Owen Taylor3473f882001-02-23 17:55:21 +000010156 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010157 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010158 int exponent = 0;
10159 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010160#ifdef __GNUC__
10161 unsigned long tmp = 0;
10162 double temp;
10163#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010164
10165 CHECK_ERROR;
10166 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10167 XP_ERROR(XPATH_NUMBER_ERROR);
10168 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010169#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010170 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010171 * tmp/temp is a workaround against a gcc compiler bug
10172 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010173 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010174 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010175 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010176 ret = ret * 10;
10177 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010178 ok = 1;
10179 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010180 temp = (double) tmp;
10181 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010182 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010183#else
10184 ret = 0;
10185 while ((CUR >= '0') && (CUR <= '9')) {
10186 ret = ret * 10 + (CUR - '0');
10187 ok = 1;
10188 NEXT;
10189 }
10190#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010191 if (CUR == '.') {
Phil Shaferee32ad32010-11-03 20:53:55 +010010192 int v, frac = 0;
10193 double fraction = 0;
10194
Owen Taylor3473f882001-02-23 17:55:21 +000010195 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010196 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10197 XP_ERROR(XPATH_NUMBER_ERROR);
10198 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010199 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10200 v = (CUR - '0');
10201 fraction = fraction * 10 + v;
10202 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010203 NEXT;
10204 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010205 fraction /= my_pow10[frac];
10206 ret = ret + fraction;
10207 while ((CUR >= '0') && (CUR <= '9'))
10208 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010209 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010210 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010211 NEXT;
10212 if (CUR == '-') {
10213 is_exponent_negative = 1;
10214 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010215 } else if (CUR == '+') {
10216 NEXT;
10217 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010218 while ((CUR >= '0') && (CUR <= '9')) {
10219 exponent = exponent * 10 + (CUR - '0');
10220 NEXT;
10221 }
10222 if (is_exponent_negative)
10223 exponent = -exponent;
10224 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010225 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010226 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010227 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010228}
10229
10230/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010231 * xmlXPathParseLiteral:
10232 * @ctxt: the XPath Parser context
10233 *
10234 * Parse a Literal
10235 *
10236 * [29] Literal ::= '"' [^"]* '"'
10237 * | "'" [^']* "'"
10238 *
10239 * Returns the value found or NULL in case of error
10240 */
10241static xmlChar *
10242xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10243 const xmlChar *q;
10244 xmlChar *ret = NULL;
10245
10246 if (CUR == '"') {
10247 NEXT;
10248 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010249 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010250 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010251 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010252 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010253 } else {
10254 ret = xmlStrndup(q, CUR_PTR - q);
10255 NEXT;
10256 }
10257 } else if (CUR == '\'') {
10258 NEXT;
10259 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010260 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010261 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010262 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010263 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010264 } else {
10265 ret = xmlStrndup(q, CUR_PTR - q);
10266 NEXT;
10267 }
10268 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010269 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010270 }
10271 return(ret);
10272}
10273
10274/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010275 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010276 * @ctxt: the XPath Parser context
10277 *
10278 * Parse a Literal and push it on the stack.
10279 *
10280 * [29] Literal ::= '"' [^"]* '"'
10281 * | "'" [^']* "'"
10282 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010283 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010284 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010285static void
10286xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010287 const xmlChar *q;
10288 xmlChar *ret = NULL;
10289
10290 if (CUR == '"') {
10291 NEXT;
10292 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010293 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010294 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010295 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010296 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10297 } else {
10298 ret = xmlStrndup(q, CUR_PTR - q);
10299 NEXT;
10300 }
10301 } else if (CUR == '\'') {
10302 NEXT;
10303 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010304 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010305 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010306 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010307 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10308 } else {
10309 ret = xmlStrndup(q, CUR_PTR - q);
10310 NEXT;
10311 }
10312 } else {
10313 XP_ERROR(XPATH_START_LITERAL_ERROR);
10314 }
10315 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010316 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010317 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010318 xmlFree(ret);
10319}
10320
10321/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010322 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010323 * @ctxt: the XPath Parser context
10324 *
10325 * Parse a VariableReference, evaluate it and push it on the stack.
10326 *
10327 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010328 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010329 * of any of the types that are possible for the value of an expression,
10330 * and may also be of additional types not specified here.
10331 *
10332 * Early evaluation is possible since:
10333 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010334 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010335 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010336 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010337 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010338static void
10339xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010340 xmlChar *name;
10341 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010342
10343 SKIP_BLANKS;
10344 if (CUR != '$') {
10345 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10346 }
10347 NEXT;
10348 name = xmlXPathParseQName(ctxt, &prefix);
10349 if (name == NULL) {
10350 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10351 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010352 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010353 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10354 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010355 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010356 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10357 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10358 }
Owen Taylor3473f882001-02-23 17:55:21 +000010359}
10360
10361/**
10362 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010363 * @name: a name string
10364 *
10365 * Is the name given a NodeType one.
10366 *
10367 * [38] NodeType ::= 'comment'
10368 * | 'text'
10369 * | 'processing-instruction'
10370 * | 'node'
10371 *
10372 * Returns 1 if true 0 otherwise
10373 */
10374int
10375xmlXPathIsNodeType(const xmlChar *name) {
10376 if (name == NULL)
10377 return(0);
10378
Daniel Veillard1971ee22002-01-31 20:29:19 +000010379 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010380 return(1);
10381 if (xmlStrEqual(name, BAD_CAST "text"))
10382 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010383 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010384 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010385 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010386 return(1);
10387 return(0);
10388}
10389
10390/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010391 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010392 * @ctxt: the XPath Parser context
10393 *
10394 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010395 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010396 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010397 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010398 * pushed on the stack
10399 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010400static void
10401xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010402 xmlChar *name;
10403 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010404 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010405 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010406
10407 name = xmlXPathParseQName(ctxt, &prefix);
10408 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010409 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010410 XP_ERROR(XPATH_EXPR_ERROR);
10411 }
10412 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010413#ifdef DEBUG_EXPR
10414 if (prefix == NULL)
10415 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10416 name);
10417 else
10418 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10419 prefix, name);
10420#endif
10421
Owen Taylor3473f882001-02-23 17:55:21 +000010422 if (CUR != '(') {
10423 XP_ERROR(XPATH_EXPR_ERROR);
10424 }
10425 NEXT;
10426 SKIP_BLANKS;
10427
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010428 /*
10429 * Optimization for count(): we don't need the node-set to be sorted.
10430 */
10431 if ((prefix == NULL) && (name[0] == 'c') &&
10432 xmlStrEqual(name, BAD_CAST "count"))
10433 {
10434 sort = 0;
10435 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010436 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010437 if (CUR != ')') {
10438 while (CUR != 0) {
10439 int op1 = ctxt->comp->last;
10440 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010441 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010442 if (ctxt->error != XPATH_EXPRESSION_OK) {
10443 xmlFree(name);
10444 xmlFree(prefix);
10445 return;
10446 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010447 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10448 nbargs++;
10449 if (CUR == ')') break;
10450 if (CUR != ',') {
10451 XP_ERROR(XPATH_EXPR_ERROR);
10452 }
10453 NEXT;
10454 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010455 }
Owen Taylor3473f882001-02-23 17:55:21 +000010456 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010457 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10458 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010459 NEXT;
10460 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010461}
10462
10463/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010464 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010465 * @ctxt: the XPath Parser context
10466 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010467 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010468 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010469 * | Literal
10470 * | Number
10471 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010472 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010473 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010474 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010475static void
10476xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010477 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010478 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010479 else if (CUR == '(') {
10480 NEXT;
10481 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010482 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010483 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010484 if (CUR != ')') {
10485 XP_ERROR(XPATH_EXPR_ERROR);
10486 }
10487 NEXT;
10488 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010489 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010490 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010491 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010492 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010493 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010494 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010495 }
10496 SKIP_BLANKS;
10497}
10498
10499/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010500 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010501 * @ctxt: the XPath Parser context
10502 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010503 * [20] FilterExpr ::= PrimaryExpr
10504 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010505 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010506 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010507 * Square brackets are used to filter expressions in the same way that
10508 * they are used in location paths. It is an error if the expression to
10509 * be filtered does not evaluate to a node-set. The context node list
10510 * used for evaluating the expression in square brackets is the node-set
10511 * to be filtered listed in document order.
10512 */
10513
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010514static void
10515xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10516 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010517 CHECK_ERROR;
10518 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010519
Owen Taylor3473f882001-02-23 17:55:21 +000010520 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010521 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010522 SKIP_BLANKS;
10523 }
10524
Daniel Veillard45490ae2008-07-29 09:13:19 +000010525
Owen Taylor3473f882001-02-23 17:55:21 +000010526}
10527
10528/**
10529 * xmlXPathScanName:
10530 * @ctxt: the XPath Parser context
10531 *
10532 * Trickery: parse an XML name but without consuming the input flow
10533 * Needed to avoid insanity in the parser state.
10534 *
10535 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10536 * CombiningChar | Extender
10537 *
10538 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10539 *
10540 * [6] Names ::= Name (S Name)*
10541 *
10542 * Returns the Name parsed or NULL
10543 */
10544
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010545static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010546xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010547 int len = 0, l;
10548 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010549 const xmlChar *cur;
10550 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010551
Daniel Veillard03226812004-11-01 14:55:21 +000010552 cur = ctxt->cur;
10553
10554 c = CUR_CHAR(l);
10555 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10556 (!IS_LETTER(c) && (c != '_') &&
10557 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010558 return(NULL);
10559 }
10560
Daniel Veillard03226812004-11-01 14:55:21 +000010561 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10562 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10563 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010564 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010565 (IS_COMBINING(c)) ||
10566 (IS_EXTENDER(c)))) {
10567 len += l;
10568 NEXTL(l);
10569 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010570 }
Daniel Veillard03226812004-11-01 14:55:21 +000010571 ret = xmlStrndup(cur, ctxt->cur - cur);
10572 ctxt->cur = cur;
10573 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010574}
10575
10576/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010577 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010578 * @ctxt: the XPath Parser context
10579 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010580 * [19] PathExpr ::= LocationPath
10581 * | FilterExpr
10582 * | FilterExpr '/' RelativeLocationPath
10583 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010584 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010585 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010586 * The / operator and // operators combine an arbitrary expression
10587 * and a relative location path. It is an error if the expression
10588 * does not evaluate to a node-set.
10589 * The / operator does composition in the same way as when / is
10590 * used in a location path. As in location paths, // is short for
10591 * /descendant-or-self::node()/.
10592 */
10593
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010594static void
10595xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010596 int lc = 1; /* Should we branch to LocationPath ? */
10597 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10598
10599 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010600 if ((CUR == '$') || (CUR == '(') ||
10601 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010602 (CUR == '\'') || (CUR == '"') ||
10603 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010604 lc = 0;
10605 } else if (CUR == '*') {
10606 /* relative or absolute location path */
10607 lc = 1;
10608 } else if (CUR == '/') {
10609 /* relative or absolute location path */
10610 lc = 1;
10611 } else if (CUR == '@') {
10612 /* relative abbreviated attribute location path */
10613 lc = 1;
10614 } else if (CUR == '.') {
10615 /* relative abbreviated attribute location path */
10616 lc = 1;
10617 } else {
10618 /*
10619 * Problem is finding if we have a name here whether it's:
10620 * - a nodetype
10621 * - a function call in which case it's followed by '('
10622 * - an axis in which case it's followed by ':'
10623 * - a element name
10624 * We do an a priori analysis here rather than having to
10625 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010626 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010627 * read/write/debug.
10628 */
10629 SKIP_BLANKS;
10630 name = xmlXPathScanName(ctxt);
10631 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10632#ifdef DEBUG_STEP
10633 xmlGenericError(xmlGenericErrorContext,
10634 "PathExpr: Axis\n");
10635#endif
10636 lc = 1;
10637 xmlFree(name);
10638 } else if (name != NULL) {
10639 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010640
Daniel Veillard45490ae2008-07-29 09:13:19 +000010641
Owen Taylor3473f882001-02-23 17:55:21 +000010642 while (NXT(len) != 0) {
10643 if (NXT(len) == '/') {
10644 /* element name */
10645#ifdef DEBUG_STEP
10646 xmlGenericError(xmlGenericErrorContext,
10647 "PathExpr: AbbrRelLocation\n");
10648#endif
10649 lc = 1;
10650 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010651 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010652 /* ignore blanks */
10653 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010654 } else if (NXT(len) == ':') {
10655#ifdef DEBUG_STEP
10656 xmlGenericError(xmlGenericErrorContext,
10657 "PathExpr: AbbrRelLocation\n");
10658#endif
10659 lc = 1;
10660 break;
10661 } else if ((NXT(len) == '(')) {
10662 /* Note Type or Function */
10663 if (xmlXPathIsNodeType(name)) {
10664#ifdef DEBUG_STEP
10665 xmlGenericError(xmlGenericErrorContext,
10666 "PathExpr: Type search\n");
10667#endif
10668 lc = 1;
10669 } else {
10670#ifdef DEBUG_STEP
10671 xmlGenericError(xmlGenericErrorContext,
10672 "PathExpr: function call\n");
10673#endif
10674 lc = 0;
10675 }
10676 break;
10677 } else if ((NXT(len) == '[')) {
10678 /* element name */
10679#ifdef DEBUG_STEP
10680 xmlGenericError(xmlGenericErrorContext,
10681 "PathExpr: AbbrRelLocation\n");
10682#endif
10683 lc = 1;
10684 break;
10685 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10686 (NXT(len) == '=')) {
10687 lc = 1;
10688 break;
10689 } else {
10690 lc = 1;
10691 break;
10692 }
10693 len++;
10694 }
10695 if (NXT(len) == 0) {
10696#ifdef DEBUG_STEP
10697 xmlGenericError(xmlGenericErrorContext,
10698 "PathExpr: AbbrRelLocation\n");
10699#endif
10700 /* element name */
10701 lc = 1;
10702 }
10703 xmlFree(name);
10704 } else {
William M. Brack08171912003-12-29 02:52:11 +000010705 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010706 XP_ERROR(XPATH_EXPR_ERROR);
10707 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010708 }
Owen Taylor3473f882001-02-23 17:55:21 +000010709
10710 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010711 if (CUR == '/') {
10712 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10713 } else {
10714 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010715 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010716 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010717 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010718 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010719 CHECK_ERROR;
10720 if ((CUR == '/') && (NXT(1) == '/')) {
10721 SKIP(2);
10722 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010723
10724 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10725 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10726 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10727
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010728 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010729 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010730 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010731 }
10732 }
10733 SKIP_BLANKS;
10734}
10735
10736/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010737 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010738 * @ctxt: the XPath Parser context
10739 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010740 * [18] UnionExpr ::= PathExpr
10741 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010742 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010743 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010744 */
10745
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010746static void
10747xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10748 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010749 CHECK_ERROR;
10750 SKIP_BLANKS;
10751 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010752 int op1 = ctxt->comp->last;
10753 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010754
10755 NEXT;
10756 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010757 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010758
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010759 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10760
Owen Taylor3473f882001-02-23 17:55:21 +000010761 SKIP_BLANKS;
10762 }
Owen Taylor3473f882001-02-23 17:55:21 +000010763}
10764
10765/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010766 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010767 * @ctxt: the XPath Parser context
10768 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010769 * [27] UnaryExpr ::= UnionExpr
10770 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010771 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010772 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010773 */
10774
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010775static void
10776xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010777 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010778 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010779
10780 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010781 while (CUR == '-') {
10782 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010783 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010784 NEXT;
10785 SKIP_BLANKS;
10786 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010787
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010788 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010789 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010790 if (found) {
10791 if (minus)
10792 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10793 else
10794 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010795 }
10796}
10797
10798/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010799 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010800 * @ctxt: the XPath Parser context
10801 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010802 * [26] MultiplicativeExpr ::= UnaryExpr
10803 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10804 * | MultiplicativeExpr 'div' UnaryExpr
10805 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010806 * [34] MultiplyOperator ::= '*'
10807 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010808 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010809 */
10810
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010811static void
10812xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10813 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010814 CHECK_ERROR;
10815 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010816 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010817 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10818 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10819 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010820 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010821
10822 if (CUR == '*') {
10823 op = 0;
10824 NEXT;
10825 } else if (CUR == 'd') {
10826 op = 1;
10827 SKIP(3);
10828 } else if (CUR == 'm') {
10829 op = 2;
10830 SKIP(3);
10831 }
10832 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010833 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010834 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010835 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010836 SKIP_BLANKS;
10837 }
10838}
10839
10840/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010841 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010842 * @ctxt: the XPath Parser context
10843 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010844 * [25] AdditiveExpr ::= MultiplicativeExpr
10845 * | AdditiveExpr '+' MultiplicativeExpr
10846 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010847 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010848 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010849 */
10850
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010851static void
10852xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010853
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010854 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010855 CHECK_ERROR;
10856 SKIP_BLANKS;
10857 while ((CUR == '+') || (CUR == '-')) {
10858 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010859 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010860
10861 if (CUR == '+') plus = 1;
10862 else plus = 0;
10863 NEXT;
10864 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010865 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010866 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010867 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010868 SKIP_BLANKS;
10869 }
10870}
10871
10872/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010873 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010874 * @ctxt: the XPath Parser context
10875 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010876 * [24] RelationalExpr ::= AdditiveExpr
10877 * | RelationalExpr '<' AdditiveExpr
10878 * | RelationalExpr '>' AdditiveExpr
10879 * | RelationalExpr '<=' AdditiveExpr
10880 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010881 *
10882 * A <= B > C is allowed ? Answer from James, yes with
10883 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10884 * which is basically what got implemented.
10885 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010886 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010887 * on the stack
10888 */
10889
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010890static void
10891xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10892 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010893 CHECK_ERROR;
10894 SKIP_BLANKS;
10895 while ((CUR == '<') ||
10896 (CUR == '>') ||
10897 ((CUR == '<') && (NXT(1) == '=')) ||
10898 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010899 int inf, strict;
10900 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010901
10902 if (CUR == '<') inf = 1;
10903 else inf = 0;
10904 if (NXT(1) == '=') strict = 0;
10905 else strict = 1;
10906 NEXT;
10907 if (!strict) NEXT;
10908 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010909 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010910 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010911 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010912 SKIP_BLANKS;
10913 }
10914}
10915
10916/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010917 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010918 * @ctxt: the XPath Parser context
10919 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010920 * [23] EqualityExpr ::= RelationalExpr
10921 * | EqualityExpr '=' RelationalExpr
10922 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010923 *
10924 * A != B != C is allowed ? Answer from James, yes with
10925 * (RelationalExpr = RelationalExpr) = RelationalExpr
10926 * (RelationalExpr != RelationalExpr) != RelationalExpr
10927 * which is basically what got implemented.
10928 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010929 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010930 *
10931 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010932static void
10933xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10934 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010935 CHECK_ERROR;
10936 SKIP_BLANKS;
10937 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010938 int eq;
10939 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010940
10941 if (CUR == '=') eq = 1;
10942 else eq = 0;
10943 NEXT;
10944 if (!eq) NEXT;
10945 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010946 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010947 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010948 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010949 SKIP_BLANKS;
10950 }
10951}
10952
10953/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010954 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010955 * @ctxt: the XPath Parser context
10956 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010957 * [22] AndExpr ::= EqualityExpr
10958 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010959 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010960 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010961 *
10962 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010963static void
10964xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10965 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010966 CHECK_ERROR;
10967 SKIP_BLANKS;
10968 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010969 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010970 SKIP(3);
10971 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010972 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010973 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010974 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010975 SKIP_BLANKS;
10976 }
10977}
10978
10979/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010980 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010981 * @ctxt: the XPath Parser context
10982 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010983 * [14] Expr ::= OrExpr
10984 * [21] OrExpr ::= AndExpr
10985 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010986 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010987 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010988 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010989static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010990xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010991 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010992 CHECK_ERROR;
10993 SKIP_BLANKS;
10994 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010995 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010996 SKIP(2);
10997 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010998 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010999 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011000 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011001 SKIP_BLANKS;
11002 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011003 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011004 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011005 /*
11006 * This is the main place to eliminate sorting for
11007 * operations which don't require a sorted node-set.
11008 * E.g. count().
11009 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011010 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11011 }
Owen Taylor3473f882001-02-23 17:55:21 +000011012}
11013
11014/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011015 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000011016 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011017 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000011018 *
11019 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000011020 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000011021 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011022 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000011023 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011024static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011025xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011026 int op1 = ctxt->comp->last;
11027
11028 SKIP_BLANKS;
11029 if (CUR != '[') {
11030 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11031 }
11032 NEXT;
11033 SKIP_BLANKS;
11034
11035 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011036 /*
11037 * This call to xmlXPathCompileExpr() will deactivate sorting
11038 * of the predicate result.
11039 * TODO: Sorting is still activated for filters, since I'm not
11040 * sure if needed. Normally sorting should not be needed, since
11041 * a filter can only diminish the number of items in a sequence,
11042 * but won't change its order; so if the initial sequence is sorted,
11043 * subsequent sorting is not needed.
11044 */
11045 if (! filter)
11046 xmlXPathCompileExpr(ctxt, 0);
11047 else
11048 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011049 CHECK_ERROR;
11050
11051 if (CUR != ']') {
11052 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11053 }
11054
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011055 if (filter)
11056 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11057 else
11058 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011059
11060 NEXT;
11061 SKIP_BLANKS;
11062}
11063
11064/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011065 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011066 * @ctxt: the XPath Parser context
11067 * @test: pointer to a xmlXPathTestVal
11068 * @type: pointer to a xmlXPathTypeVal
11069 * @prefix: placeholder for a possible name prefix
11070 *
11071 * [7] NodeTest ::= NameTest
11072 * | NodeType '(' ')'
11073 * | 'processing-instruction' '(' Literal ')'
11074 *
11075 * [37] NameTest ::= '*'
11076 * | NCName ':' '*'
11077 * | QName
11078 * [38] NodeType ::= 'comment'
11079 * | 'text'
11080 * | 'processing-instruction'
11081 * | 'node'
11082 *
William M. Brack08171912003-12-29 02:52:11 +000011083 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011084 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011085static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011086xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11087 xmlXPathTypeVal *type, const xmlChar **prefix,
11088 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011089 int blanks;
11090
11091 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11092 STRANGE;
11093 return(NULL);
11094 }
William M. Brack78637da2003-07-31 14:47:38 +000011095 *type = (xmlXPathTypeVal) 0;
11096 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011097 *prefix = NULL;
11098 SKIP_BLANKS;
11099
11100 if ((name == NULL) && (CUR == '*')) {
11101 /*
11102 * All elements
11103 */
11104 NEXT;
11105 *test = NODE_TEST_ALL;
11106 return(NULL);
11107 }
11108
11109 if (name == NULL)
11110 name = xmlXPathParseNCName(ctxt);
11111 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011112 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011113 }
11114
William M. Brack76e95df2003-10-18 16:20:14 +000011115 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011116 SKIP_BLANKS;
11117 if (CUR == '(') {
11118 NEXT;
11119 /*
11120 * NodeType or PI search
11121 */
11122 if (xmlStrEqual(name, BAD_CAST "comment"))
11123 *type = NODE_TYPE_COMMENT;
11124 else if (xmlStrEqual(name, BAD_CAST "node"))
11125 *type = NODE_TYPE_NODE;
11126 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11127 *type = NODE_TYPE_PI;
11128 else if (xmlStrEqual(name, BAD_CAST "text"))
11129 *type = NODE_TYPE_TEXT;
11130 else {
11131 if (name != NULL)
11132 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011133 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011134 }
11135
11136 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011137
Owen Taylor3473f882001-02-23 17:55:21 +000011138 SKIP_BLANKS;
11139 if (*type == NODE_TYPE_PI) {
11140 /*
11141 * Specific case: search a PI by name.
11142 */
Owen Taylor3473f882001-02-23 17:55:21 +000011143 if (name != NULL)
11144 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011145 name = NULL;
11146 if (CUR != ')') {
11147 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011148 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011149 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011150 SKIP_BLANKS;
11151 }
Owen Taylor3473f882001-02-23 17:55:21 +000011152 }
11153 if (CUR != ')') {
11154 if (name != NULL)
11155 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011156 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011157 }
11158 NEXT;
11159 return(name);
11160 }
11161 *test = NODE_TEST_NAME;
11162 if ((!blanks) && (CUR == ':')) {
11163 NEXT;
11164
11165 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011166 * Since currently the parser context don't have a
11167 * namespace list associated:
11168 * The namespace name for this prefix can be computed
11169 * only at evaluation time. The compilation is done
11170 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011171 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011172#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011173 *prefix = xmlXPathNsLookup(ctxt->context, name);
11174 if (name != NULL)
11175 xmlFree(name);
11176 if (*prefix == NULL) {
11177 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11178 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011179#else
11180 *prefix = name;
11181#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011182
11183 if (CUR == '*') {
11184 /*
11185 * All elements
11186 */
11187 NEXT;
11188 *test = NODE_TEST_ALL;
11189 return(NULL);
11190 }
11191
11192 name = xmlXPathParseNCName(ctxt);
11193 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011194 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011195 }
11196 }
11197 return(name);
11198}
11199
11200/**
11201 * xmlXPathIsAxisName:
11202 * @name: a preparsed name token
11203 *
11204 * [6] AxisName ::= 'ancestor'
11205 * | 'ancestor-or-self'
11206 * | 'attribute'
11207 * | 'child'
11208 * | 'descendant'
11209 * | 'descendant-or-self'
11210 * | 'following'
11211 * | 'following-sibling'
11212 * | 'namespace'
11213 * | 'parent'
11214 * | 'preceding'
11215 * | 'preceding-sibling'
11216 * | 'self'
11217 *
11218 * Returns the axis or 0
11219 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011220static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011221xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011222 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011223 switch (name[0]) {
11224 case 'a':
11225 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11226 ret = AXIS_ANCESTOR;
11227 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11228 ret = AXIS_ANCESTOR_OR_SELF;
11229 if (xmlStrEqual(name, BAD_CAST "attribute"))
11230 ret = AXIS_ATTRIBUTE;
11231 break;
11232 case 'c':
11233 if (xmlStrEqual(name, BAD_CAST "child"))
11234 ret = AXIS_CHILD;
11235 break;
11236 case 'd':
11237 if (xmlStrEqual(name, BAD_CAST "descendant"))
11238 ret = AXIS_DESCENDANT;
11239 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11240 ret = AXIS_DESCENDANT_OR_SELF;
11241 break;
11242 case 'f':
11243 if (xmlStrEqual(name, BAD_CAST "following"))
11244 ret = AXIS_FOLLOWING;
11245 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11246 ret = AXIS_FOLLOWING_SIBLING;
11247 break;
11248 case 'n':
11249 if (xmlStrEqual(name, BAD_CAST "namespace"))
11250 ret = AXIS_NAMESPACE;
11251 break;
11252 case 'p':
11253 if (xmlStrEqual(name, BAD_CAST "parent"))
11254 ret = AXIS_PARENT;
11255 if (xmlStrEqual(name, BAD_CAST "preceding"))
11256 ret = AXIS_PRECEDING;
11257 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11258 ret = AXIS_PRECEDING_SIBLING;
11259 break;
11260 case 's':
11261 if (xmlStrEqual(name, BAD_CAST "self"))
11262 ret = AXIS_SELF;
11263 break;
11264 }
11265 return(ret);
11266}
11267
11268/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011269 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011270 * @ctxt: the XPath Parser context
11271 *
11272 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011273 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011274 *
11275 * [12] AbbreviatedStep ::= '.' | '..'
11276 *
11277 * [5] AxisSpecifier ::= AxisName '::'
11278 * | AbbreviatedAxisSpecifier
11279 *
11280 * [13] AbbreviatedAxisSpecifier ::= '@'?
11281 *
11282 * Modified for XPtr range support as:
11283 *
11284 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11285 * | AbbreviatedStep
11286 * | 'range-to' '(' Expr ')' Predicate*
11287 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011288 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011289 * A location step of . is short for self::node(). This is
11290 * particularly useful in conjunction with //. For example, the
11291 * location path .//para is short for
11292 * self::node()/descendant-or-self::node()/child::para
11293 * and so will select all para descendant elements of the context
11294 * node.
11295 * Similarly, a location step of .. is short for parent::node().
11296 * For example, ../title is short for parent::node()/child::title
11297 * and so will select the title children of the parent of the context
11298 * node.
11299 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011300static void
11301xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011302#ifdef LIBXML_XPTR_ENABLED
11303 int rangeto = 0;
11304 int op2 = -1;
11305#endif
11306
Owen Taylor3473f882001-02-23 17:55:21 +000011307 SKIP_BLANKS;
11308 if ((CUR == '.') && (NXT(1) == '.')) {
11309 SKIP(2);
11310 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011311 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11312 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011313 } else if (CUR == '.') {
11314 NEXT;
11315 SKIP_BLANKS;
11316 } else {
11317 xmlChar *name = NULL;
11318 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011319 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011320 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011321 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011322 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011323
11324 /*
11325 * The modification needed for XPointer change to the production
11326 */
11327#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011328 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011329 name = xmlXPathParseNCName(ctxt);
11330 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011331 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011332 xmlFree(name);
11333 SKIP_BLANKS;
11334 if (CUR != '(') {
11335 XP_ERROR(XPATH_EXPR_ERROR);
11336 }
11337 NEXT;
11338 SKIP_BLANKS;
11339
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011340 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011341 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011342 CHECK_ERROR;
11343
11344 SKIP_BLANKS;
11345 if (CUR != ')') {
11346 XP_ERROR(XPATH_EXPR_ERROR);
11347 }
11348 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011349 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011350 goto eval_predicates;
11351 }
11352 }
11353#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011354 if (CUR == '*') {
11355 axis = AXIS_CHILD;
11356 } else {
11357 if (name == NULL)
11358 name = xmlXPathParseNCName(ctxt);
11359 if (name != NULL) {
11360 axis = xmlXPathIsAxisName(name);
11361 if (axis != 0) {
11362 SKIP_BLANKS;
11363 if ((CUR == ':') && (NXT(1) == ':')) {
11364 SKIP(2);
11365 xmlFree(name);
11366 name = NULL;
11367 } else {
11368 /* an element name can conflict with an axis one :-\ */
11369 axis = AXIS_CHILD;
11370 }
Owen Taylor3473f882001-02-23 17:55:21 +000011371 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011372 axis = AXIS_CHILD;
11373 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011374 } else if (CUR == '@') {
11375 NEXT;
11376 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011377 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011378 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011379 }
Owen Taylor3473f882001-02-23 17:55:21 +000011380 }
11381
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011382 if (ctxt->error != XPATH_EXPRESSION_OK) {
11383 xmlFree(name);
11384 return;
11385 }
Owen Taylor3473f882001-02-23 17:55:21 +000011386
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011387 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011388 if (test == 0)
11389 return;
11390
Daniel Veillarded6c5492005-07-23 15:00:22 +000011391 if ((prefix != NULL) && (ctxt->context != NULL) &&
11392 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11393 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11394 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11395 }
11396 }
Owen Taylor3473f882001-02-23 17:55:21 +000011397#ifdef DEBUG_STEP
11398 xmlGenericError(xmlGenericErrorContext,
11399 "Basis : computing new set\n");
11400#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011401
Owen Taylor3473f882001-02-23 17:55:21 +000011402#ifdef DEBUG_STEP
11403 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011404 if (ctxt->value == NULL)
11405 xmlGenericError(xmlGenericErrorContext, "no value\n");
11406 else if (ctxt->value->nodesetval == NULL)
11407 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11408 else
11409 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011410#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011411
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011412#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011413eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011414#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011415 op1 = ctxt->comp->last;
11416 ctxt->comp->last = -1;
11417
Owen Taylor3473f882001-02-23 17:55:21 +000011418 SKIP_BLANKS;
11419 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011420 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011421 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011422
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011423#ifdef LIBXML_XPTR_ENABLED
11424 if (rangeto) {
11425 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11426 } else
11427#endif
11428 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11429 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011430
Owen Taylor3473f882001-02-23 17:55:21 +000011431 }
11432#ifdef DEBUG_STEP
11433 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011434 if (ctxt->value == NULL)
11435 xmlGenericError(xmlGenericErrorContext, "no value\n");
11436 else if (ctxt->value->nodesetval == NULL)
11437 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11438 else
11439 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11440 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011441#endif
11442}
11443
11444/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011445 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011446 * @ctxt: the XPath Parser context
11447 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011448 * [3] RelativeLocationPath ::= Step
11449 * | RelativeLocationPath '/' Step
11450 * | AbbreviatedRelativeLocationPath
11451 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011452 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011453 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011454 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011455static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011456xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011457(xmlXPathParserContextPtr ctxt) {
11458 SKIP_BLANKS;
11459 if ((CUR == '/') && (NXT(1) == '/')) {
11460 SKIP(2);
11461 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011462 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11463 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011464 } else if (CUR == '/') {
11465 NEXT;
11466 SKIP_BLANKS;
11467 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011468 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011469 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011470 SKIP_BLANKS;
11471 while (CUR == '/') {
11472 if ((CUR == '/') && (NXT(1) == '/')) {
11473 SKIP(2);
11474 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011475 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011476 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011477 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011478 } else if (CUR == '/') {
11479 NEXT;
11480 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011481 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011482 }
11483 SKIP_BLANKS;
11484 }
11485}
11486
11487/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011488 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011489 * @ctxt: the XPath Parser context
11490 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011491 * [1] LocationPath ::= RelativeLocationPath
11492 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011493 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011494 * | AbbreviatedAbsoluteLocationPath
11495 * [10] AbbreviatedAbsoluteLocationPath ::=
11496 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011497 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011498 * Compile a location path
11499 *
Owen Taylor3473f882001-02-23 17:55:21 +000011500 * // is short for /descendant-or-self::node()/. For example,
11501 * //para is short for /descendant-or-self::node()/child::para and
11502 * so will select any para element in the document (even a para element
11503 * that is a document element will be selected by //para since the
11504 * document element node is a child of the root node); div//para is
11505 * short for div/descendant-or-self::node()/child::para and so will
11506 * select all para descendants of div children.
11507 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011508static void
11509xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011510 SKIP_BLANKS;
11511 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011512 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011513 } else {
11514 while (CUR == '/') {
11515 if ((CUR == '/') && (NXT(1) == '/')) {
11516 SKIP(2);
11517 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011518 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11519 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011520 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011521 } else if (CUR == '/') {
11522 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011523 SKIP_BLANKS;
11524 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011525 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011526 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011527 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011528 }
Martin729601f2009-10-12 22:42:26 +020011529 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011530 }
11531 }
11532}
11533
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011534/************************************************************************
11535 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011536 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011537 * *
11538 ************************************************************************/
11539
Daniel Veillardf06307e2001-07-03 10:35:50 +000011540static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011541xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11542
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011543#ifdef DEBUG_STEP
11544static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011545xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011546 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011547{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011548 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011549 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011550 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011551 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011552 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011553 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011554 xmlGenericError(xmlGenericErrorContext,
11555 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011556 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011557 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011558 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011559 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011560 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011561 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011562 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011563 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011564 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011565 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011566 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011567 xmlGenericError(xmlGenericErrorContext,
11568 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011569 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011570 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011571 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011572 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011573 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011574 xmlGenericError(xmlGenericErrorContext,
11575 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011576 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011577 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011578 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011579 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011580 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011581 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011582 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011583 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011584 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011585 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011586 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011587 xmlGenericError(xmlGenericErrorContext,
11588 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011589 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011590 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011591 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011592 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011593 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011594 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011595 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011596 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011597 case NODE_TEST_NONE:
11598 xmlGenericError(xmlGenericErrorContext,
11599 " searching for none !!!\n");
11600 break;
11601 case NODE_TEST_TYPE:
11602 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011603 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011604 break;
11605 case NODE_TEST_PI:
11606 xmlGenericError(xmlGenericErrorContext,
11607 " searching for PI !!!\n");
11608 break;
11609 case NODE_TEST_ALL:
11610 xmlGenericError(xmlGenericErrorContext,
11611 " searching for *\n");
11612 break;
11613 case NODE_TEST_NS:
11614 xmlGenericError(xmlGenericErrorContext,
11615 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011616 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011617 break;
11618 case NODE_TEST_NAME:
11619 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011620 " searching for name %s\n", op->value5);
11621 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011622 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011623 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011624 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011625 }
11626 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011627}
11628#endif /* DEBUG_STEP */
11629
11630static int
11631xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11632 xmlXPathStepOpPtr op,
11633 xmlNodeSetPtr set,
11634 int contextSize,
11635 int hasNsNodes)
11636{
11637 if (op->ch1 != -1) {
11638 xmlXPathCompExprPtr comp = ctxt->comp;
11639 /*
11640 * Process inner predicates first.
11641 */
11642 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11643 /*
11644 * TODO: raise an internal error.
11645 */
11646 }
11647 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11648 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11649 CHECK_ERROR0;
11650 if (contextSize <= 0)
11651 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011652 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011653 if (op->ch2 != -1) {
11654 xmlXPathContextPtr xpctxt = ctxt->context;
11655 xmlNodePtr contextNode, oldContextNode;
11656 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011657 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011658 xmlXPathStepOpPtr exprOp;
11659 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11660
11661#ifdef LIBXML_XPTR_ENABLED
11662 /*
11663 * URGENT TODO: Check the following:
11664 * We don't expect location sets if evaluating prediates, right?
11665 * Only filters should expect location sets, right?
11666 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011667#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011668 /*
11669 * SPEC XPath 1.0:
11670 * "For each node in the node-set to be filtered, the
11671 * PredicateExpr is evaluated with that node as the
11672 * context node, with the number of nodes in the
11673 * node-set as the context size, and with the proximity
11674 * position of the node in the node-set with respect to
11675 * the axis as the context position;"
11676 * @oldset is the node-set" to be filtered.
11677 *
11678 * SPEC XPath 1.0:
11679 * "only predicates change the context position and
11680 * context size (see [2.4 Predicates])."
11681 * Example:
11682 * node-set context pos
11683 * nA 1
11684 * nB 2
11685 * nC 3
11686 * After applying predicate [position() > 1] :
11687 * node-set context pos
11688 * nB 1
11689 * nC 2
11690 */
11691 oldContextNode = xpctxt->node;
11692 oldContextDoc = xpctxt->doc;
11693 /*
11694 * Get the expression of this predicate.
11695 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011696 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011697 newContextSize = 0;
11698 for (i = 0; i < set->nodeNr; i++) {
11699 if (set->nodeTab[i] == NULL)
11700 continue;
11701
11702 contextNode = set->nodeTab[i];
11703 xpctxt->node = contextNode;
11704 xpctxt->contextSize = contextSize;
11705 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011706
11707 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011708 * Also set the xpath document in case things like
11709 * key() are evaluated in the predicate.
11710 */
11711 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11712 (contextNode->doc != NULL))
11713 xpctxt->doc = contextNode->doc;
11714 /*
11715 * Evaluate the predicate expression with 1 context node
11716 * at a time; this node is packaged into a node set; this
11717 * node set is handed over to the evaluation mechanism.
11718 */
11719 if (contextObj == NULL)
11720 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11721 else
11722 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11723 contextNode);
11724
11725 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011726
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011727 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011728
William M. Brack0bcec062007-02-14 02:15:19 +000011729 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11730 xmlXPathNodeSetClear(set, hasNsNodes);
11731 newContextSize = 0;
11732 goto evaluation_exit;
11733 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011734
11735 if (res != 0) {
11736 newContextSize++;
11737 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011738 /*
11739 * Remove the entry from the initial node set.
11740 */
11741 set->nodeTab[i] = NULL;
11742 if (contextNode->type == XML_NAMESPACE_DECL)
11743 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011744 }
11745 if (ctxt->value == contextObj) {
11746 /*
11747 * Don't free the temporary XPath object holding the
11748 * context node, in order to avoid massive recreation
11749 * inside this loop.
11750 */
11751 valuePop(ctxt);
11752 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11753 } else {
11754 /*
11755 * TODO: The object was lost in the evaluation machinery.
11756 * Can this happen? Maybe in internal-error cases.
11757 */
11758 contextObj = NULL;
11759 }
11760 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011761
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011762 if (contextObj != NULL) {
11763 if (ctxt->value == contextObj)
11764 valuePop(ctxt);
11765 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011766 }
William M. Brack0bcec062007-02-14 02:15:19 +000011767evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011768 if (exprRes != NULL)
11769 xmlXPathReleaseObject(ctxt->context, exprRes);
11770 /*
11771 * Reset/invalidate the context.
11772 */
11773 xpctxt->node = oldContextNode;
11774 xpctxt->doc = oldContextDoc;
11775 xpctxt->contextSize = -1;
11776 xpctxt->proximityPosition = -1;
11777 return(newContextSize);
11778 }
11779 return(contextSize);
11780}
11781
11782static int
11783xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11784 xmlXPathStepOpPtr op,
11785 xmlNodeSetPtr set,
11786 int contextSize,
11787 int minPos,
11788 int maxPos,
11789 int hasNsNodes)
11790{
11791 if (op->ch1 != -1) {
11792 xmlXPathCompExprPtr comp = ctxt->comp;
11793 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11794 /*
11795 * TODO: raise an internal error.
11796 */
11797 }
11798 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11799 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11800 CHECK_ERROR0;
11801 if (contextSize <= 0)
11802 return(0);
11803 }
11804 /*
11805 * Check if the node set contains a sufficient number of nodes for
11806 * the requested range.
11807 */
11808 if (contextSize < minPos) {
11809 xmlXPathNodeSetClear(set, hasNsNodes);
11810 return(0);
11811 }
11812 if (op->ch2 == -1) {
11813 /*
11814 * TODO: Can this ever happen?
11815 */
11816 return (contextSize);
11817 } else {
11818 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011819 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011820 xmlXPathStepOpPtr exprOp;
11821 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11822 xmlNodePtr oldContextNode, contextNode = NULL;
11823 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011824 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011825
11826#ifdef LIBXML_XPTR_ENABLED
11827 /*
11828 * URGENT TODO: Check the following:
11829 * We don't expect location sets if evaluating prediates, right?
11830 * Only filters should expect location sets, right?
11831 */
11832#endif /* LIBXML_XPTR_ENABLED */
11833
11834 /*
11835 * Save old context.
11836 */
11837 oldContextNode = xpctxt->node;
11838 oldContextDoc = xpctxt->doc;
11839 /*
11840 * Get the expression of this predicate.
11841 */
11842 exprOp = &ctxt->comp->steps[op->ch2];
11843 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011844 xmlXPathObjectPtr tmp;
11845
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011846 if (set->nodeTab[i] == NULL)
11847 continue;
11848
11849 contextNode = set->nodeTab[i];
11850 xpctxt->node = contextNode;
11851 xpctxt->contextSize = contextSize;
11852 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011853
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011854 /*
11855 * Initialize the new set.
11856 * Also set the xpath document in case things like
11857 * key() evaluation are attempted on the predicate
11858 */
11859 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11860 (contextNode->doc != NULL))
11861 xpctxt->doc = contextNode->doc;
11862 /*
11863 * Evaluate the predicate expression with 1 context node
11864 * at a time; this node is packaged into a node set; this
11865 * node set is handed over to the evaluation mechanism.
11866 */
11867 if (contextObj == NULL)
11868 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11869 else
11870 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11871 contextNode);
11872
Daniel Veillardf5048b32011-08-18 17:10:13 +080011873 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011874 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011875 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011876 tmp = valuePop(ctxt);
11877 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011878
William M. Brackf1794562007-08-23 12:58:13 +000011879 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011880 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011881 /*
11882 * Free up the result
11883 * then pop off contextObj, which will be freed later
11884 */
11885 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011886 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011887 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011888 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011889 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011890 /* push the result back onto the stack */
11891 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011892
11893 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011894 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011895
11896 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011897 /*
11898 * Fits in the requested range.
11899 */
11900 newContextSize++;
11901 if (minPos == maxPos) {
11902 /*
11903 * Only 1 node was requested.
11904 */
11905 if (contextNode->type == XML_NAMESPACE_DECL) {
11906 /*
11907 * As always: take care of those nasty
11908 * namespace nodes.
11909 */
11910 set->nodeTab[i] = NULL;
11911 }
11912 xmlXPathNodeSetClear(set, hasNsNodes);
11913 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011914 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011915 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011916 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011917 if (pos == maxPos) {
11918 /*
11919 * We are done.
11920 */
11921 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11922 goto evaluation_exit;
11923 }
11924 } else {
11925 /*
11926 * Remove the entry from the initial node set.
11927 */
11928 set->nodeTab[i] = NULL;
11929 if (contextNode->type == XML_NAMESPACE_DECL)
11930 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11931 }
11932 if (exprRes != NULL) {
11933 xmlXPathReleaseObject(ctxt->context, exprRes);
11934 exprRes = NULL;
11935 }
11936 if (ctxt->value == contextObj) {
11937 /*
11938 * Don't free the temporary XPath object holding the
11939 * context node, in order to avoid massive recreation
11940 * inside this loop.
11941 */
11942 valuePop(ctxt);
11943 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11944 } else {
11945 /*
11946 * The object was lost in the evaluation machinery.
11947 * Can this happen? Maybe in case of internal-errors.
11948 */
11949 contextObj = NULL;
11950 }
11951 }
11952 goto evaluation_exit;
11953
11954evaluation_error:
11955 xmlXPathNodeSetClear(set, hasNsNodes);
11956 newContextSize = 0;
11957
11958evaluation_exit:
11959 if (contextObj != NULL) {
11960 if (ctxt->value == contextObj)
11961 valuePop(ctxt);
11962 xmlXPathReleaseObject(xpctxt, contextObj);
11963 }
11964 if (exprRes != NULL)
11965 xmlXPathReleaseObject(ctxt->context, exprRes);
11966 /*
11967 * Reset/invalidate the context.
11968 */
11969 xpctxt->node = oldContextNode;
11970 xpctxt->doc = oldContextDoc;
11971 xpctxt->contextSize = -1;
11972 xpctxt->proximityPosition = -1;
11973 return(newContextSize);
11974 }
11975 return(contextSize);
11976}
11977
11978static int
11979xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000011980 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011981 int *maxPos)
11982{
11983
11984 xmlXPathStepOpPtr exprOp;
11985
11986 /*
11987 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11988 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011989
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011990 /*
11991 * If not -1, then ch1 will point to:
11992 * 1) For predicates (XPATH_OP_PREDICATE):
11993 * - an inner predicate operator
11994 * 2) For filters (XPATH_OP_FILTER):
11995 * - an inner filter operater OR
11996 * - an expression selecting the node set.
11997 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000011998 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011999 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12000 return(0);
12001
12002 if (op->ch2 != -1) {
12003 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012004 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012005 return(0);
12006
12007 if ((exprOp != NULL) &&
12008 (exprOp->op == XPATH_OP_VALUE) &&
12009 (exprOp->value4 != NULL) &&
12010 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12011 {
12012 /*
12013 * We have a "[n]" predicate here.
12014 * TODO: Unfortunately this simplistic test here is not
12015 * able to detect a position() predicate in compound
12016 * expressions like "[@attr = 'a" and position() = 1],
12017 * and even not the usage of position() in
12018 * "[position() = 1]"; thus - obviously - a position-range,
12019 * like it "[position() < 5]", is also not detected.
12020 * Maybe we could rewrite the AST to ease the optimization.
12021 */
12022 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012023
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012024 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12025 (float) *maxPos)
Daniel Veillard45490ae2008-07-29 09:13:19 +000012026 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012027 return(1);
12028 }
12029 }
12030 return(0);
12031}
12032
12033static int
12034xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12035 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012036 xmlNodePtr * first, xmlNodePtr * last,
12037 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012038{
12039
12040#define XP_TEST_HIT \
12041 if (hasAxisRange != 0) { \
12042 if (++pos == maxPos) { \
12043 addNode(seq, cur); \
12044 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012045 } else { \
12046 addNode(seq, cur); \
12047 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012048
12049#define XP_TEST_HIT_NS \
12050 if (hasAxisRange != 0) { \
12051 if (++pos == maxPos) { \
12052 hasNsNodes = 1; \
12053 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
12054 goto axis_range_end; } \
12055 } else { \
12056 hasNsNodes = 1; \
12057 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012058 xpctxt->node, (xmlNsPtr) cur); \
12059 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012060
12061 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12062 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12063 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12064 const xmlChar *prefix = op->value4;
12065 const xmlChar *name = op->value5;
12066 const xmlChar *URI = NULL;
12067
12068#ifdef DEBUG_STEP
12069 int nbMatches = 0, prevMatches = 0;
12070#endif
12071 int total = 0, hasNsNodes = 0;
12072 /* The popped object holding the context nodes */
12073 xmlXPathObjectPtr obj;
12074 /* The set of context nodes for the node tests */
12075 xmlNodeSetPtr contextSeq;
12076 int contextIdx;
12077 xmlNodePtr contextNode;
12078 /* The context node for a compound traversal */
12079 xmlNodePtr outerContextNode;
12080 /* The final resulting node set wrt to all context nodes */
12081 xmlNodeSetPtr outSeq;
12082 /*
12083 * The temporary resulting node set wrt 1 context node.
12084 * Used to feed predicate evaluation.
12085 */
12086 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012087 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012088 /* First predicate operator */
12089 xmlXPathStepOpPtr predOp;
12090 int maxPos; /* The requested position() (when a "[n]" predicate) */
12091 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012092 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012093
12094 xmlXPathTraversalFunction next = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012095 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12096 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012097 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012098 xmlXPathContextPtr xpctxt = ctxt->context;
12099
12100
12101 CHECK_TYPE0(XPATH_NODESET);
12102 obj = valuePop(ctxt);
12103 /*
12104 * Setup namespaces.
12105 */
12106 if (prefix != NULL) {
12107 URI = xmlXPathNsLookup(xpctxt, prefix);
12108 if (URI == NULL) {
12109 xmlXPathReleaseObject(xpctxt, obj);
12110 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12111 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012112 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012113 /*
12114 * Setup axis.
12115 *
12116 * MAYBE FUTURE TODO: merging optimizations:
12117 * - If the nodes to be traversed wrt to the initial nodes and
12118 * the current axis cannot overlap, then we could avoid searching
12119 * for duplicates during the merge.
12120 * But the question is how/when to evaluate if they cannot overlap.
12121 * Example: if we know that for two initial nodes, the one is
12122 * not in the ancestor-or-self axis of the other, then we could safely
12123 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12124 * the descendant-or-self axis.
12125 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012126 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12127 switch (axis) {
12128 case AXIS_ANCESTOR:
12129 first = NULL;
12130 next = xmlXPathNextAncestor;
12131 break;
12132 case AXIS_ANCESTOR_OR_SELF:
12133 first = NULL;
12134 next = xmlXPathNextAncestorOrSelf;
12135 break;
12136 case AXIS_ATTRIBUTE:
12137 first = NULL;
12138 last = NULL;
12139 next = xmlXPathNextAttribute;
12140 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12141 break;
12142 case AXIS_CHILD:
12143 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012144 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12145 (type == NODE_TYPE_NODE))
12146 {
12147 /*
12148 * Optimization if an element node type is 'element'.
12149 */
12150 next = xmlXPathNextChildElement;
12151 } else
12152 next = xmlXPathNextChild;
12153 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12154 break;
12155 case AXIS_DESCENDANT:
12156 last = NULL;
12157 next = xmlXPathNextDescendant;
12158 break;
12159 case AXIS_DESCENDANT_OR_SELF:
12160 last = NULL;
12161 next = xmlXPathNextDescendantOrSelf;
12162 break;
12163 case AXIS_FOLLOWING:
12164 last = NULL;
12165 next = xmlXPathNextFollowing;
12166 break;
12167 case AXIS_FOLLOWING_SIBLING:
12168 last = NULL;
12169 next = xmlXPathNextFollowingSibling;
12170 break;
12171 case AXIS_NAMESPACE:
12172 first = NULL;
12173 last = NULL;
12174 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12175 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12176 break;
12177 case AXIS_PARENT:
12178 first = NULL;
12179 next = xmlXPathNextParent;
12180 break;
12181 case AXIS_PRECEDING:
12182 first = NULL;
12183 next = xmlXPathNextPrecedingInternal;
12184 break;
12185 case AXIS_PRECEDING_SIBLING:
12186 first = NULL;
12187 next = xmlXPathNextPrecedingSibling;
12188 break;
12189 case AXIS_SELF:
12190 first = NULL;
12191 last = NULL;
12192 next = xmlXPathNextSelf;
12193 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12194 break;
12195 }
12196
12197#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012198 xmlXPathDebugDumpStepAxis(op,
12199 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012200#endif
12201
12202 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012203 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012204 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012205 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012206 contextSeq = obj->nodesetval;
12207 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12208 xmlXPathReleaseObject(xpctxt, obj);
12209 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12210 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012211 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012212 /*
12213 * Predicate optimization ---------------------------------------------
12214 * If this step has a last predicate, which contains a position(),
12215 * then we'll optimize (although not exactly "position()", but only
12216 * the short-hand form, i.e., "[n]".
12217 *
12218 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012219 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012220 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12221 * ROOT -- op->ch1
12222 * PREDICATE -- op->ch2 (predOp)
12223 * PREDICATE -- predOp->ch1 = [parent::bar]
12224 * SORT
12225 * COLLECT 'parent' 'name' 'node' bar
12226 * NODE
12227 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12228 *
12229 */
12230 maxPos = 0;
12231 predOp = NULL;
12232 hasPredicateRange = 0;
12233 hasAxisRange = 0;
12234 if (op->ch2 != -1) {
12235 /*
12236 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12237 */
12238 predOp = &ctxt->comp->steps[op->ch2];
12239 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12240 if (predOp->ch1 != -1) {
12241 /*
12242 * Use the next inner predicate operator.
12243 */
12244 predOp = &ctxt->comp->steps[predOp->ch1];
12245 hasPredicateRange = 1;
12246 } else {
12247 /*
12248 * There's no other predicate than the [n] predicate.
12249 */
12250 predOp = NULL;
12251 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012252 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012253 }
12254 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012255 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012256 /*
12257 * Axis traversal -----------------------------------------------------
12258 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012259 /*
12260 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012261 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012262 * - For the namespace axis, the principal node type is namespace.
12263 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012264 *
12265 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012266 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012267 * select all element children of the context node
12268 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012269 oldContextNode = xpctxt->node;
12270 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012271 outSeq = NULL;
12272 seq = NULL;
12273 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012274 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012275 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012276
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012277
12278 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012279 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012280
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012281 if (seq == NULL) {
12282 seq = xmlXPathNodeSetCreate(NULL);
12283 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012284 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012285 goto error;
12286 }
12287 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012288 /*
12289 * Traverse the axis and test the nodes.
12290 */
12291 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012292 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012293 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012294 do {
12295 cur = next(ctxt, cur);
12296 if (cur == NULL)
12297 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012298
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012299 /*
12300 * QUESTION TODO: What does the "first" and "last" stuff do?
12301 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012302 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012303 if (*first == cur)
12304 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012305 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012306#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012307 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012308#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012309 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012310#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012311 {
12312 break;
12313 }
12314 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012315 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012316 if (*last == cur)
12317 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012318 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012319#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012320 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012321#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012322 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012323#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012324 {
12325 break;
12326 }
12327 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012328
12329 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012330
Daniel Veillardf06307e2001-07-03 10:35:50 +000012331#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012332 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12333#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012334
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012335 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012336 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012337 total = 0;
12338 STRANGE
12339 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012340 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012341 /*
12342 * TODO: Don't we need to use
12343 * xmlXPathNodeSetAddNs() for namespace nodes here?
12344 * Surprisingly, some c14n tests fail, if we do this.
12345 */
12346 if (type == NODE_TYPE_NODE) {
12347 switch (cur->type) {
12348 case XML_DOCUMENT_NODE:
12349 case XML_HTML_DOCUMENT_NODE:
12350#ifdef LIBXML_DOCB_ENABLED
12351 case XML_DOCB_DOCUMENT_NODE:
12352#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012353 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012354 case XML_ATTRIBUTE_NODE:
12355 case XML_PI_NODE:
12356 case XML_COMMENT_NODE:
12357 case XML_CDATA_SECTION_NODE:
12358 case XML_TEXT_NODE:
12359 case XML_NAMESPACE_DECL:
12360 XP_TEST_HIT
12361 break;
12362 default:
12363 break;
12364 }
12365 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012366 if (type == XML_NAMESPACE_DECL)
12367 XP_TEST_HIT_NS
12368 else
12369 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012370 } else if ((type == NODE_TYPE_TEXT) &&
12371 (cur->type == XML_CDATA_SECTION_NODE))
12372 {
12373 XP_TEST_HIT
12374 }
12375 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012376 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012377 if ((cur->type == XML_PI_NODE) &&
12378 ((name == NULL) || xmlStrEqual(name, cur->name)))
12379 {
12380 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012381 }
12382 break;
12383 case NODE_TEST_ALL:
12384 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012385 if (cur->type == XML_ATTRIBUTE_NODE)
12386 {
12387 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012388 }
12389 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012390 if (cur->type == XML_NAMESPACE_DECL)
12391 {
12392 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012393 }
12394 } else {
12395 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012396 if (prefix == NULL)
12397 {
12398 XP_TEST_HIT
12399
Daniel Veillardf06307e2001-07-03 10:35:50 +000012400 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012401 (xmlStrEqual(URI, cur->ns->href)))
12402 {
12403 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012404 }
12405 }
12406 }
12407 break;
12408 case NODE_TEST_NS:{
12409 TODO;
12410 break;
12411 }
12412 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012413 if (axis == AXIS_ATTRIBUTE) {
12414 if (cur->type != XML_ATTRIBUTE_NODE)
12415 break;
12416 } else if (axis == AXIS_NAMESPACE) {
12417 if (cur->type != XML_NAMESPACE_DECL)
12418 break;
12419 } else {
12420 if (cur->type != XML_ELEMENT_NODE)
12421 break;
12422 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012423 switch (cur->type) {
12424 case XML_ELEMENT_NODE:
12425 if (xmlStrEqual(name, cur->name)) {
12426 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012427 if (cur->ns == NULL)
12428 {
12429 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012430 }
12431 } else {
12432 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012433 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012434 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012435 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012436 }
12437 }
12438 }
12439 break;
12440 case XML_ATTRIBUTE_NODE:{
12441 xmlAttrPtr attr = (xmlAttrPtr) cur;
12442
12443 if (xmlStrEqual(name, attr->name)) {
12444 if (prefix == NULL) {
12445 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012446 (attr->ns->prefix == NULL))
12447 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012448 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012449 }
12450 } else {
12451 if ((attr->ns != NULL) &&
12452 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012453 attr->ns->href)))
12454 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012455 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012456 }
12457 }
12458 }
12459 break;
12460 }
12461 case XML_NAMESPACE_DECL:
12462 if (cur->type == XML_NAMESPACE_DECL) {
12463 xmlNsPtr ns = (xmlNsPtr) cur;
12464
12465 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012466 && (xmlStrEqual(ns->prefix, name)))
12467 {
12468 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012469 }
12470 }
12471 break;
12472 default:
12473 break;
12474 }
12475 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012476 } /* switch(test) */
12477 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012478
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012479 goto apply_predicates;
12480
Daniel Veillard45490ae2008-07-29 09:13:19 +000012481axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012482 /*
12483 * We have a "/foo[n]", and position() = n was reached.
12484 * Note that we can have as well "/foo/::parent::foo[1]", so
12485 * a duplicate-aware merge is still needed.
12486 * Merge with the result.
12487 */
12488 if (outSeq == NULL) {
12489 outSeq = seq;
12490 seq = NULL;
12491 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012492 outSeq = mergeAndClear(outSeq, seq, 0);
12493 /*
12494 * Break if only a true/false result was requested.
12495 */
12496 if (toBool)
12497 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012498 continue;
12499
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012500first_hit: /* ---------------------------------------------------------- */
12501 /*
12502 * Break if only a true/false result was requested and
12503 * no predicates existed and a node test succeeded.
12504 */
12505 if (outSeq == NULL) {
12506 outSeq = seq;
12507 seq = NULL;
12508 } else
12509 outSeq = mergeAndClear(outSeq, seq, 0);
12510 break;
12511
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012512#ifdef DEBUG_STEP
12513 if (seq != NULL)
12514 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012515#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012516
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012517apply_predicates: /* --------------------------------------------------- */
12518 /*
12519 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012520 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012521 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12522 /*
12523 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012524 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012525 /*
12526 * QUESTION TODO: The old predicate evaluation took into
12527 * account location-sets.
12528 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12529 * Do we expect such a set here?
12530 * All what I learned now from the evaluation semantics
12531 * does not indicate that a location-set will be processed
12532 * here, so this looks OK.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012533 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012534 /*
12535 * Iterate over all predicates, starting with the outermost
12536 * predicate.
12537 * TODO: Problem: we cannot execute the inner predicates first
12538 * since we cannot go back *up* the operator tree!
12539 * Options we have:
12540 * 1) Use of recursive functions (like is it currently done
12541 * via xmlXPathCompOpEval())
12542 * 2) Add a predicate evaluation information stack to the
12543 * context struct
12544 * 3) Change the way the operators are linked; we need a
12545 * "parent" field on xmlXPathStepOp
12546 *
12547 * For the moment, I'll try to solve this with a recursive
12548 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012549 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012550 size = seq->nodeNr;
12551 if (hasPredicateRange != 0)
12552 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12553 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12554 else
12555 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12556 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012557
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012558 if (ctxt->error != XPATH_EXPRESSION_OK) {
12559 total = 0;
12560 goto error;
12561 }
12562 /*
12563 * Add the filtered set of nodes to the result node set.
12564 */
12565 if (newSize == 0) {
12566 /*
12567 * The predicates filtered all nodes out.
12568 */
12569 xmlXPathNodeSetClear(seq, hasNsNodes);
12570 } else if (seq->nodeNr > 0) {
12571 /*
12572 * Add to result set.
12573 */
12574 if (outSeq == NULL) {
12575 if (size != newSize) {
12576 /*
12577 * We need to merge and clear here, since
12578 * the sequence will contained NULLed entries.
12579 */
12580 outSeq = mergeAndClear(NULL, seq, 1);
12581 } else {
12582 outSeq = seq;
12583 seq = NULL;
12584 }
12585 } else
12586 outSeq = mergeAndClear(outSeq, seq,
12587 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012588 /*
12589 * Break if only a true/false result was requested.
12590 */
12591 if (toBool)
12592 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012593 }
12594 } else if (seq->nodeNr > 0) {
12595 /*
12596 * Add to result set.
12597 */
12598 if (outSeq == NULL) {
12599 outSeq = seq;
12600 seq = NULL;
12601 } else {
12602 outSeq = mergeAndClear(outSeq, seq, 0);
12603 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012604 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012605 }
12606
12607error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012608 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012609 /*
12610 * QUESTION TODO: What does this do and why?
12611 * TODO: Do we have to do this also for the "error"
12612 * cleanup further down?
12613 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012614 ctxt->value->boolval = 1;
12615 ctxt->value->user = obj->user;
12616 obj->user = NULL;
12617 obj->boolval = 0;
12618 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012619 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012620
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012621 /*
12622 * Ensure we return at least an emtpy set.
12623 */
12624 if (outSeq == NULL) {
12625 if ((seq != NULL) && (seq->nodeNr == 0))
12626 outSeq = seq;
12627 else
12628 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012629 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012630 }
12631 if ((seq != NULL) && (seq != outSeq)) {
12632 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012633 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012634 /*
12635 * Hand over the result. Better to push the set also in
12636 * case of errors.
12637 */
12638 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12639 /*
12640 * Reset the context node.
12641 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012642 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012643
12644#ifdef DEBUG_STEP
12645 xmlGenericError(xmlGenericErrorContext,
12646 "\nExamined %d nodes, found %d nodes at that step\n",
12647 total, nbMatches);
12648#endif
12649
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012650 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012651}
12652
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012653static int
12654xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12655 xmlXPathStepOpPtr op, xmlNodePtr * first);
12656
Daniel Veillardf06307e2001-07-03 10:35:50 +000012657/**
12658 * xmlXPathCompOpEvalFirst:
12659 * @ctxt: the XPath parser context with the compiled expression
12660 * @op: an XPath compiled operation
12661 * @first: the first elem found so far
12662 *
12663 * Evaluate the Precompiled XPath operation searching only the first
12664 * element in document order
12665 *
12666 * Returns the number of examined objects.
12667 */
12668static int
12669xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12670 xmlXPathStepOpPtr op, xmlNodePtr * first)
12671{
12672 int total = 0, cur;
12673 xmlXPathCompExprPtr comp;
12674 xmlXPathObjectPtr arg1, arg2;
12675
Daniel Veillard556c6682001-10-06 09:59:51 +000012676 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012677 comp = ctxt->comp;
12678 switch (op->op) {
12679 case XPATH_OP_END:
12680 return (0);
12681 case XPATH_OP_UNION:
12682 total =
12683 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12684 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012685 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012686 if ((ctxt->value != NULL)
12687 && (ctxt->value->type == XPATH_NODESET)
12688 && (ctxt->value->nodesetval != NULL)
12689 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12690 /*
12691 * limit tree traversing to first node in the result
12692 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012693 /*
12694 * OPTIMIZE TODO: This implicitely sorts
12695 * the result, even if not needed. E.g. if the argument
12696 * of the count() function, no sorting is needed.
12697 * OPTIMIZE TODO: How do we know if the node-list wasn't
12698 * aready sorted?
12699 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012700 if (ctxt->value->nodesetval->nodeNr > 1)
12701 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012702 *first = ctxt->value->nodesetval->nodeTab[0];
12703 }
12704 cur =
12705 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12706 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012707 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012708 CHECK_TYPE0(XPATH_NODESET);
12709 arg2 = valuePop(ctxt);
12710
12711 CHECK_TYPE0(XPATH_NODESET);
12712 arg1 = valuePop(ctxt);
12713
12714 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12715 arg2->nodesetval);
12716 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012717 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012718 /* optimizer */
12719 if (total > cur)
12720 xmlXPathCompSwap(op);
12721 return (total + cur);
12722 case XPATH_OP_ROOT:
12723 xmlXPathRoot(ctxt);
12724 return (0);
12725 case XPATH_OP_NODE:
12726 if (op->ch1 != -1)
12727 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012728 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012729 if (op->ch2 != -1)
12730 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012731 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012732 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12733 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012734 return (total);
12735 case XPATH_OP_RESET:
12736 if (op->ch1 != -1)
12737 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012738 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012739 if (op->ch2 != -1)
12740 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012741 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012742 ctxt->context->node = NULL;
12743 return (total);
12744 case XPATH_OP_COLLECT:{
12745 if (op->ch1 == -1)
12746 return (total);
12747
12748 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012749 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012750
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012751 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012752 return (total);
12753 }
12754 case XPATH_OP_VALUE:
12755 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012756 xmlXPathCacheObjectCopy(ctxt->context,
12757 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012758 return (0);
12759 case XPATH_OP_SORT:
12760 if (op->ch1 != -1)
12761 total +=
12762 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12763 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012764 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012765 if ((ctxt->value != NULL)
12766 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012767 && (ctxt->value->nodesetval != NULL)
12768 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012769 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12770 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012771#ifdef XP_OPTIMIZED_FILTER_FIRST
12772 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012773 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012774 return (total);
12775#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012776 default:
12777 return (xmlXPathCompOpEval(ctxt, op));
12778 }
12779}
12780
12781/**
12782 * xmlXPathCompOpEvalLast:
12783 * @ctxt: the XPath parser context with the compiled expression
12784 * @op: an XPath compiled operation
12785 * @last: the last elem found so far
12786 *
12787 * Evaluate the Precompiled XPath operation searching only the last
12788 * element in document order
12789 *
William M. Brack08171912003-12-29 02:52:11 +000012790 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012791 */
12792static int
12793xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12794 xmlNodePtr * last)
12795{
12796 int total = 0, cur;
12797 xmlXPathCompExprPtr comp;
12798 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012799 xmlNodePtr bak;
12800 xmlDocPtr bakd;
12801 int pp;
12802 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012803
Daniel Veillard556c6682001-10-06 09:59:51 +000012804 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012805 comp = ctxt->comp;
12806 switch (op->op) {
12807 case XPATH_OP_END:
12808 return (0);
12809 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012810 bakd = ctxt->context->doc;
12811 bak = ctxt->context->node;
12812 pp = ctxt->context->proximityPosition;
12813 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012814 total =
12815 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012816 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012817 if ((ctxt->value != NULL)
12818 && (ctxt->value->type == XPATH_NODESET)
12819 && (ctxt->value->nodesetval != NULL)
12820 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12821 /*
12822 * limit tree traversing to first node in the result
12823 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012824 if (ctxt->value->nodesetval->nodeNr > 1)
12825 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012826 *last =
12827 ctxt->value->nodesetval->nodeTab[ctxt->value->
12828 nodesetval->nodeNr -
12829 1];
12830 }
William M. Brackce4fc562004-01-22 02:47:18 +000012831 ctxt->context->doc = bakd;
12832 ctxt->context->node = bak;
12833 ctxt->context->proximityPosition = pp;
12834 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012835 cur =
12836 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012837 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012838 if ((ctxt->value != NULL)
12839 && (ctxt->value->type == XPATH_NODESET)
12840 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012841 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012842 }
12843 CHECK_TYPE0(XPATH_NODESET);
12844 arg2 = valuePop(ctxt);
12845
12846 CHECK_TYPE0(XPATH_NODESET);
12847 arg1 = valuePop(ctxt);
12848
12849 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12850 arg2->nodesetval);
12851 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012852 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012853 /* optimizer */
12854 if (total > cur)
12855 xmlXPathCompSwap(op);
12856 return (total + cur);
12857 case XPATH_OP_ROOT:
12858 xmlXPathRoot(ctxt);
12859 return (0);
12860 case XPATH_OP_NODE:
12861 if (op->ch1 != -1)
12862 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012863 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012864 if (op->ch2 != -1)
12865 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012866 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012867 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12868 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012869 return (total);
12870 case XPATH_OP_RESET:
12871 if (op->ch1 != -1)
12872 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012873 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012874 if (op->ch2 != -1)
12875 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012876 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012877 ctxt->context->node = NULL;
12878 return (total);
12879 case XPATH_OP_COLLECT:{
12880 if (op->ch1 == -1)
12881 return (0);
12882
12883 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012884 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012885
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012886 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012887 return (total);
12888 }
12889 case XPATH_OP_VALUE:
12890 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012891 xmlXPathCacheObjectCopy(ctxt->context,
12892 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012893 return (0);
12894 case XPATH_OP_SORT:
12895 if (op->ch1 != -1)
12896 total +=
12897 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12898 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012899 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012900 if ((ctxt->value != NULL)
12901 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012902 && (ctxt->value->nodesetval != NULL)
12903 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012904 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12905 return (total);
12906 default:
12907 return (xmlXPathCompOpEval(ctxt, op));
12908 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012909}
12910
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012911#ifdef XP_OPTIMIZED_FILTER_FIRST
12912static int
12913xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12914 xmlXPathStepOpPtr op, xmlNodePtr * first)
12915{
12916 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012917 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012918 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012919 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012920 xmlNodeSetPtr oldset;
12921 xmlNodePtr oldnode;
12922 xmlDocPtr oldDoc;
12923 int i;
12924
12925 CHECK_ERROR0;
12926 comp = ctxt->comp;
12927 /*
12928 * Optimization for ()[last()] selection i.e. the last elem
12929 */
12930 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12931 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12932 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12933 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012934
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012935 if ((f != -1) &&
12936 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12937 (comp->steps[f].value5 == NULL) &&
12938 (comp->steps[f].value == 0) &&
12939 (comp->steps[f].value4 != NULL) &&
12940 (xmlStrEqual
12941 (comp->steps[f].value4, BAD_CAST "last"))) {
12942 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012943
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012944 total +=
12945 xmlXPathCompOpEvalLast(ctxt,
12946 &comp->steps[op->ch1],
12947 &last);
12948 CHECK_ERROR0;
12949 /*
12950 * The nodeset should be in document order,
12951 * Keep only the last value
12952 */
12953 if ((ctxt->value != NULL) &&
12954 (ctxt->value->type == XPATH_NODESET) &&
12955 (ctxt->value->nodesetval != NULL) &&
12956 (ctxt->value->nodesetval->nodeTab != NULL) &&
12957 (ctxt->value->nodesetval->nodeNr > 1)) {
12958 ctxt->value->nodesetval->nodeTab[0] =
12959 ctxt->value->nodesetval->nodeTab[ctxt->
12960 value->
12961 nodesetval->
12962 nodeNr -
12963 1];
12964 ctxt->value->nodesetval->nodeNr = 1;
12965 *first = *(ctxt->value->nodesetval->nodeTab);
12966 }
12967 return (total);
12968 }
12969 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012970
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012971 if (op->ch1 != -1)
12972 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12973 CHECK_ERROR0;
12974 if (op->ch2 == -1)
12975 return (total);
12976 if (ctxt->value == NULL)
12977 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012978
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012979#ifdef LIBXML_XPTR_ENABLED
12980 oldnode = ctxt->context->node;
12981 /*
12982 * Hum are we filtering the result of an XPointer expression
12983 */
12984 if (ctxt->value->type == XPATH_LOCATIONSET) {
12985 xmlXPathObjectPtr tmp = NULL;
12986 xmlLocationSetPtr newlocset = NULL;
12987 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012988
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012989 /*
12990 * Extract the old locset, and then evaluate the result of the
12991 * expression for all the element in the locset. use it to grow
12992 * up a new locset.
12993 */
12994 CHECK_TYPE0(XPATH_LOCATIONSET);
12995 obj = valuePop(ctxt);
12996 oldlocset = obj->user;
12997 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012998
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012999 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13000 ctxt->context->contextSize = 0;
13001 ctxt->context->proximityPosition = 0;
13002 if (op->ch2 != -1)
13003 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13004 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013005 if (res != NULL) {
13006 xmlXPathReleaseObject(ctxt->context, res);
13007 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013008 valuePush(ctxt, obj);
13009 CHECK_ERROR0;
13010 return (total);
13011 }
13012 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013013
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013014 for (i = 0; i < oldlocset->locNr; i++) {
13015 /*
13016 * Run the evaluation with a node list made of a
13017 * single item in the nodelocset.
13018 */
13019 ctxt->context->node = oldlocset->locTab[i]->user;
13020 ctxt->context->contextSize = oldlocset->locNr;
13021 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013022 if (tmp == NULL) {
13023 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13024 ctxt->context->node);
13025 } else {
13026 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13027 ctxt->context->node);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013028 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013029 valuePush(ctxt, tmp);
13030 if (op->ch2 != -1)
13031 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13032 if (ctxt->error != XPATH_EXPRESSION_OK) {
13033 xmlXPathFreeObject(obj);
13034 return(0);
13035 }
13036 /*
13037 * The result of the evaluation need to be tested to
13038 * decided whether the filter succeeded or not
13039 */
13040 res = valuePop(ctxt);
13041 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13042 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013043 xmlXPathCacheObjectCopy(ctxt->context,
13044 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013045 }
13046 /*
13047 * Cleanup
13048 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013049 if (res != NULL) {
13050 xmlXPathReleaseObject(ctxt->context, res);
13051 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013052 if (ctxt->value == tmp) {
13053 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013054 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013055 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013056 * REVISIT TODO: Don't create a temporary nodeset
13057 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013058 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013059 /* OLD: xmlXPathFreeObject(res); */
13060 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013061 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013062 ctxt->context->node = NULL;
13063 /*
13064 * Only put the first node in the result, then leave.
13065 */
13066 if (newlocset->locNr > 0) {
13067 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13068 break;
13069 }
13070 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013071 if (tmp != NULL) {
13072 xmlXPathReleaseObject(ctxt->context, tmp);
13073 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013074 /*
13075 * The result is used as the new evaluation locset.
13076 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013077 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013078 ctxt->context->node = NULL;
13079 ctxt->context->contextSize = -1;
13080 ctxt->context->proximityPosition = -1;
13081 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13082 ctxt->context->node = oldnode;
13083 return (total);
13084 }
13085#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013086
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013087 /*
13088 * Extract the old set, and then evaluate the result of the
13089 * expression for all the element in the set. use it to grow
13090 * up a new set.
13091 */
13092 CHECK_TYPE0(XPATH_NODESET);
13093 obj = valuePop(ctxt);
13094 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013095
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013096 oldnode = ctxt->context->node;
13097 oldDoc = ctxt->context->doc;
13098 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013099
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013100 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13101 ctxt->context->contextSize = 0;
13102 ctxt->context->proximityPosition = 0;
13103 /* QUESTION TODO: Why was this code commented out?
13104 if (op->ch2 != -1)
13105 total +=
13106 xmlXPathCompOpEval(ctxt,
13107 &comp->steps[op->ch2]);
13108 CHECK_ERROR0;
13109 res = valuePop(ctxt);
13110 if (res != NULL)
13111 xmlXPathFreeObject(res);
13112 */
13113 valuePush(ctxt, obj);
13114 ctxt->context->node = oldnode;
13115 CHECK_ERROR0;
13116 } else {
13117 xmlNodeSetPtr newset;
13118 xmlXPathObjectPtr tmp = NULL;
13119 /*
13120 * Initialize the new set.
13121 * Also set the xpath document in case things like
13122 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013123 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013124 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013125 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013126
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013127 for (i = 0; i < oldset->nodeNr; i++) {
13128 /*
13129 * Run the evaluation with a node list made of
13130 * a single item in the nodeset.
13131 */
13132 ctxt->context->node = oldset->nodeTab[i];
13133 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13134 (oldset->nodeTab[i]->doc != NULL))
13135 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013136 if (tmp == NULL) {
13137 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13138 ctxt->context->node);
13139 } else {
13140 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13141 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013142 }
13143 valuePush(ctxt, tmp);
13144 ctxt->context->contextSize = oldset->nodeNr;
13145 ctxt->context->proximityPosition = i + 1;
13146 if (op->ch2 != -1)
13147 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13148 if (ctxt->error != XPATH_EXPRESSION_OK) {
13149 xmlXPathFreeNodeSet(newset);
13150 xmlXPathFreeObject(obj);
13151 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013152 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013153 /*
13154 * The result of the evaluation needs to be tested to
13155 * decide whether the filter succeeded or not
13156 */
13157 res = valuePop(ctxt);
13158 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13159 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013160 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013161 /*
13162 * Cleanup
13163 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013164 if (res != NULL) {
13165 xmlXPathReleaseObject(ctxt->context, res);
13166 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013167 if (ctxt->value == tmp) {
13168 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013169 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013170 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013171 * in order to avoid massive recreation inside this
13172 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013173 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013174 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013175 } else
13176 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013177 ctxt->context->node = NULL;
13178 /*
13179 * Only put the first node in the result, then leave.
13180 */
13181 if (newset->nodeNr > 0) {
13182 *first = *(newset->nodeTab);
13183 break;
13184 }
13185 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013186 if (tmp != NULL) {
13187 xmlXPathReleaseObject(ctxt->context, tmp);
13188 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013189 /*
13190 * The result is used as the new evaluation set.
13191 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013192 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013193 ctxt->context->node = NULL;
13194 ctxt->context->contextSize = -1;
13195 ctxt->context->proximityPosition = -1;
13196 /* may want to move this past the '}' later */
13197 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013198 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013199 }
13200 ctxt->context->node = oldnode;
13201 return(total);
13202}
13203#endif /* XP_OPTIMIZED_FILTER_FIRST */
13204
Owen Taylor3473f882001-02-23 17:55:21 +000013205/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013206 * xmlXPathCompOpEval:
13207 * @ctxt: the XPath parser context with the compiled expression
13208 * @op: an XPath compiled operation
13209 *
13210 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013211 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013212 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013213static int
13214xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13215{
13216 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013217 int equal, ret;
13218 xmlXPathCompExprPtr comp;
13219 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013220 xmlNodePtr bak;
13221 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013222 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013223 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013224
Daniel Veillard556c6682001-10-06 09:59:51 +000013225 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013226 comp = ctxt->comp;
13227 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013228 case XPATH_OP_END:
13229 return (0);
13230 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013231 bakd = ctxt->context->doc;
13232 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013233 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013234 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013235 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013236 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013237 xmlXPathBooleanFunction(ctxt, 1);
13238 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13239 return (total);
13240 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013241 ctxt->context->doc = bakd;
13242 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013243 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013244 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013245 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013246 if (ctxt->error) {
13247 xmlXPathFreeObject(arg2);
13248 return(0);
13249 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013250 xmlXPathBooleanFunction(ctxt, 1);
13251 arg1 = valuePop(ctxt);
13252 arg1->boolval &= arg2->boolval;
13253 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013254 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013255 return (total);
13256 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013257 bakd = ctxt->context->doc;
13258 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013259 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013260 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013261 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013262 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013263 xmlXPathBooleanFunction(ctxt, 1);
13264 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13265 return (total);
13266 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013267 ctxt->context->doc = bakd;
13268 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013269 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013270 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013271 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013272 if (ctxt->error) {
13273 xmlXPathFreeObject(arg2);
13274 return(0);
13275 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013276 xmlXPathBooleanFunction(ctxt, 1);
13277 arg1 = valuePop(ctxt);
13278 arg1->boolval |= arg2->boolval;
13279 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013280 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013281 return (total);
13282 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013283 bakd = ctxt->context->doc;
13284 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013285 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013286 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013287 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013288 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013289 ctxt->context->doc = bakd;
13290 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013291 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013292 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013293 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013294 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013295 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013296 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013297 else
13298 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013299 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013300 return (total);
13301 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013302 bakd = ctxt->context->doc;
13303 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013304 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013305 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013306 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013307 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013308 ctxt->context->doc = bakd;
13309 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013310 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013311 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013312 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013313 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013314 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013315 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013316 return (total);
13317 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013318 bakd = ctxt->context->doc;
13319 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013320 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013321 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013322 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013323 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013324 if (op->ch2 != -1) {
13325 ctxt->context->doc = bakd;
13326 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013327 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013328 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013329 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013330 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013331 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013332 if (op->value == 0)
13333 xmlXPathSubValues(ctxt);
13334 else if (op->value == 1)
13335 xmlXPathAddValues(ctxt);
13336 else if (op->value == 2)
13337 xmlXPathValueFlipSign(ctxt);
13338 else if (op->value == 3) {
13339 CAST_TO_NUMBER;
13340 CHECK_TYPE0(XPATH_NUMBER);
13341 }
13342 return (total);
13343 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013344 bakd = ctxt->context->doc;
13345 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013346 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013347 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013348 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013349 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013350 ctxt->context->doc = bakd;
13351 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013352 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013353 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013354 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013355 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013356 if (op->value == 0)
13357 xmlXPathMultValues(ctxt);
13358 else if (op->value == 1)
13359 xmlXPathDivValues(ctxt);
13360 else if (op->value == 2)
13361 xmlXPathModValues(ctxt);
13362 return (total);
13363 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013364 bakd = ctxt->context->doc;
13365 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013366 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013367 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013368 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013369 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013370 ctxt->context->doc = bakd;
13371 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013372 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013373 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013374 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013375 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013376 CHECK_TYPE0(XPATH_NODESET);
13377 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013378
Daniel Veillardf06307e2001-07-03 10:35:50 +000013379 CHECK_TYPE0(XPATH_NODESET);
13380 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013381
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013382 if ((arg1->nodesetval == NULL) ||
13383 ((arg2->nodesetval != NULL) &&
13384 (arg2->nodesetval->nodeNr != 0)))
13385 {
13386 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13387 arg2->nodesetval);
13388 }
13389
Daniel Veillardf06307e2001-07-03 10:35:50 +000013390 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013391 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013392 return (total);
13393 case XPATH_OP_ROOT:
13394 xmlXPathRoot(ctxt);
13395 return (total);
13396 case XPATH_OP_NODE:
13397 if (op->ch1 != -1)
13398 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013399 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013400 if (op->ch2 != -1)
13401 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013402 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013403 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13404 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013405 return (total);
13406 case XPATH_OP_RESET:
13407 if (op->ch1 != -1)
13408 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013409 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013410 if (op->ch2 != -1)
13411 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013412 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013413 ctxt->context->node = NULL;
13414 return (total);
13415 case XPATH_OP_COLLECT:{
13416 if (op->ch1 == -1)
13417 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013418
Daniel Veillardf06307e2001-07-03 10:35:50 +000013419 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013420 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013421
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013422 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013423 return (total);
13424 }
13425 case XPATH_OP_VALUE:
13426 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013427 xmlXPathCacheObjectCopy(ctxt->context,
13428 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013429 return (total);
13430 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013431 xmlXPathObjectPtr val;
13432
Daniel Veillardf06307e2001-07-03 10:35:50 +000013433 if (op->ch1 != -1)
13434 total +=
13435 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013436 if (op->value5 == NULL) {
13437 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13438 if (val == NULL) {
13439 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13440 return(0);
13441 }
13442 valuePush(ctxt, val);
13443 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013444 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013445
Daniel Veillardf06307e2001-07-03 10:35:50 +000013446 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13447 if (URI == NULL) {
13448 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013449 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13450 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013451 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013452 return (total);
13453 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013454 val = xmlXPathVariableLookupNS(ctxt->context,
13455 op->value4, URI);
13456 if (val == NULL) {
13457 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13458 return(0);
13459 }
13460 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013461 }
13462 return (total);
13463 }
13464 case XPATH_OP_FUNCTION:{
13465 xmlXPathFunction func;
13466 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013467 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013468 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013469
Daniel Veillardf5048b32011-08-18 17:10:13 +080013470 frame = xmlXPathSetFrame(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013471 if (op->ch1 != -1)
13472 total +=
13473 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013474 if (ctxt->valueNr < op->value) {
13475 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013476 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013477 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013478 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013479 return (total);
13480 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013481 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013482 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13483 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013484 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013485 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013486 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013487 return (total);
13488 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013489 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013490 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013491 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013492 else {
13493 const xmlChar *URI = NULL;
13494
13495 if (op->value5 == NULL)
13496 func =
13497 xmlXPathFunctionLookup(ctxt->context,
13498 op->value4);
13499 else {
13500 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13501 if (URI == NULL) {
13502 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013503 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13504 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013505 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013506 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013507 return (total);
13508 }
13509 func = xmlXPathFunctionLookupNS(ctxt->context,
13510 op->value4, URI);
13511 }
13512 if (func == NULL) {
13513 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013514 "xmlXPathCompOpEval: function %s not found\n",
13515 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013516 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013517 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013518 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013519 op->cacheURI = (void *) URI;
13520 }
13521 oldFunc = ctxt->context->function;
13522 oldFuncURI = ctxt->context->functionURI;
13523 ctxt->context->function = op->value4;
13524 ctxt->context->functionURI = op->cacheURI;
13525 func(ctxt, op->value);
13526 ctxt->context->function = oldFunc;
13527 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013528 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013529 return (total);
13530 }
13531 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013532 bakd = ctxt->context->doc;
13533 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013534 pp = ctxt->context->proximityPosition;
13535 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013536 if (op->ch1 != -1)
13537 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013538 ctxt->context->contextSize = cs;
13539 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013540 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013541 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013542 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013543 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013544 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013545 ctxt->context->doc = bakd;
13546 ctxt->context->node = bak;
13547 CHECK_ERROR0;
13548 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013549 return (total);
13550 case XPATH_OP_PREDICATE:
13551 case XPATH_OP_FILTER:{
13552 xmlXPathObjectPtr res;
13553 xmlXPathObjectPtr obj, tmp;
13554 xmlNodeSetPtr newset = NULL;
13555 xmlNodeSetPtr oldset;
13556 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013557 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013558 int i;
13559
13560 /*
13561 * Optimization for ()[1] selection i.e. the first elem
13562 */
13563 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013564#ifdef XP_OPTIMIZED_FILTER_FIRST
13565 /*
13566 * FILTER TODO: Can we assume that the inner processing
13567 * will result in an ordered list if we have an
13568 * XPATH_OP_FILTER?
13569 * What about an additional field or flag on
13570 * xmlXPathObject like @sorted ? This way we wouln'd need
13571 * to assume anything, so it would be more robust and
13572 * easier to optimize.
13573 */
13574 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13575 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13576#else
13577 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13578#endif
13579 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013580 xmlXPathObjectPtr val;
13581
13582 val = comp->steps[op->ch2].value4;
13583 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13584 (val->floatval == 1.0)) {
13585 xmlNodePtr first = NULL;
13586
13587 total +=
13588 xmlXPathCompOpEvalFirst(ctxt,
13589 &comp->steps[op->ch1],
13590 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013591 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013592 /*
13593 * The nodeset should be in document order,
13594 * Keep only the first value
13595 */
13596 if ((ctxt->value != NULL) &&
13597 (ctxt->value->type == XPATH_NODESET) &&
13598 (ctxt->value->nodesetval != NULL) &&
13599 (ctxt->value->nodesetval->nodeNr > 1))
13600 ctxt->value->nodesetval->nodeNr = 1;
13601 return (total);
13602 }
13603 }
13604 /*
13605 * Optimization for ()[last()] selection i.e. the last elem
13606 */
13607 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13608 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13609 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13610 int f = comp->steps[op->ch2].ch1;
13611
13612 if ((f != -1) &&
13613 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13614 (comp->steps[f].value5 == NULL) &&
13615 (comp->steps[f].value == 0) &&
13616 (comp->steps[f].value4 != NULL) &&
13617 (xmlStrEqual
13618 (comp->steps[f].value4, BAD_CAST "last"))) {
13619 xmlNodePtr last = NULL;
13620
13621 total +=
13622 xmlXPathCompOpEvalLast(ctxt,
13623 &comp->steps[op->ch1],
13624 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013625 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013626 /*
13627 * The nodeset should be in document order,
13628 * Keep only the last value
13629 */
13630 if ((ctxt->value != NULL) &&
13631 (ctxt->value->type == XPATH_NODESET) &&
13632 (ctxt->value->nodesetval != NULL) &&
13633 (ctxt->value->nodesetval->nodeTab != NULL) &&
13634 (ctxt->value->nodesetval->nodeNr > 1)) {
13635 ctxt->value->nodesetval->nodeTab[0] =
13636 ctxt->value->nodesetval->nodeTab[ctxt->
13637 value->
13638 nodesetval->
13639 nodeNr -
13640 1];
13641 ctxt->value->nodesetval->nodeNr = 1;
13642 }
13643 return (total);
13644 }
13645 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013646 /*
13647 * Process inner predicates first.
13648 * Example "index[parent::book][1]":
13649 * ...
13650 * PREDICATE <-- we are here "[1]"
13651 * PREDICATE <-- process "[parent::book]" first
13652 * SORT
13653 * COLLECT 'parent' 'name' 'node' book
13654 * NODE
13655 * ELEM Object is a number : 1
13656 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013657 if (op->ch1 != -1)
13658 total +=
13659 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013660 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013661 if (op->ch2 == -1)
13662 return (total);
13663 if (ctxt->value == NULL)
13664 return (total);
13665
13666 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013667
13668#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013669 /*
13670 * Hum are we filtering the result of an XPointer expression
13671 */
13672 if (ctxt->value->type == XPATH_LOCATIONSET) {
13673 xmlLocationSetPtr newlocset = NULL;
13674 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013675
Daniel Veillardf06307e2001-07-03 10:35:50 +000013676 /*
13677 * Extract the old locset, and then evaluate the result of the
13678 * expression for all the element in the locset. use it to grow
13679 * up a new locset.
13680 */
13681 CHECK_TYPE0(XPATH_LOCATIONSET);
13682 obj = valuePop(ctxt);
13683 oldlocset = obj->user;
13684 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013685
Daniel Veillardf06307e2001-07-03 10:35:50 +000013686 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13687 ctxt->context->contextSize = 0;
13688 ctxt->context->proximityPosition = 0;
13689 if (op->ch2 != -1)
13690 total +=
13691 xmlXPathCompOpEval(ctxt,
13692 &comp->steps[op->ch2]);
13693 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013694 if (res != NULL) {
13695 xmlXPathReleaseObject(ctxt->context, res);
13696 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013697 valuePush(ctxt, obj);
13698 CHECK_ERROR0;
13699 return (total);
13700 }
13701 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013702
Daniel Veillardf06307e2001-07-03 10:35:50 +000013703 for (i = 0; i < oldlocset->locNr; i++) {
13704 /*
13705 * Run the evaluation with a node list made of a
13706 * single item in the nodelocset.
13707 */
13708 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013709 ctxt->context->contextSize = oldlocset->locNr;
13710 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013711 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13712 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013713 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013714
Daniel Veillardf06307e2001-07-03 10:35:50 +000013715 if (op->ch2 != -1)
13716 total +=
13717 xmlXPathCompOpEval(ctxt,
13718 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013719 if (ctxt->error != XPATH_EXPRESSION_OK) {
13720 xmlXPathFreeObject(obj);
13721 return(0);
13722 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013723
Daniel Veillardf06307e2001-07-03 10:35:50 +000013724 /*
13725 * The result of the evaluation need to be tested to
13726 * decided whether the filter succeeded or not
13727 */
13728 res = valuePop(ctxt);
13729 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13730 xmlXPtrLocationSetAdd(newlocset,
13731 xmlXPathObjectCopy
13732 (oldlocset->locTab[i]));
13733 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013734
Daniel Veillardf06307e2001-07-03 10:35:50 +000013735 /*
13736 * Cleanup
13737 */
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 if (ctxt->value == tmp) {
13742 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013743 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013744 }
13745
13746 ctxt->context->node = NULL;
13747 }
13748
13749 /*
13750 * The result is used as the new evaluation locset.
13751 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013752 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013753 ctxt->context->node = NULL;
13754 ctxt->context->contextSize = -1;
13755 ctxt->context->proximityPosition = -1;
13756 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13757 ctxt->context->node = oldnode;
13758 return (total);
13759 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013760#endif /* LIBXML_XPTR_ENABLED */
13761
Daniel Veillardf06307e2001-07-03 10:35:50 +000013762 /*
13763 * Extract the old set, and then evaluate the result of the
13764 * expression for all the element in the set. use it to grow
13765 * up a new set.
13766 */
13767 CHECK_TYPE0(XPATH_NODESET);
13768 obj = valuePop(ctxt);
13769 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013770
Daniel Veillardf06307e2001-07-03 10:35:50 +000013771 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013772 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013773 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013774
Daniel Veillardf06307e2001-07-03 10:35:50 +000013775 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13776 ctxt->context->contextSize = 0;
13777 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013778/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013779 if (op->ch2 != -1)
13780 total +=
13781 xmlXPathCompOpEval(ctxt,
13782 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013783 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013784 res = valuePop(ctxt);
13785 if (res != NULL)
13786 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013787*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013788 valuePush(ctxt, obj);
13789 ctxt->context->node = oldnode;
13790 CHECK_ERROR0;
13791 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013792 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013793 /*
13794 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013795 * Also set the xpath document in case things like
13796 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013797 */
13798 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013799 /*
13800 * SPEC XPath 1.0:
13801 * "For each node in the node-set to be filtered, the
13802 * PredicateExpr is evaluated with that node as the
13803 * context node, with the number of nodes in the
13804 * node-set as the context size, and with the proximity
13805 * position of the node in the node-set with respect to
13806 * the axis as the context position;"
13807 * @oldset is the node-set" to be filtered.
13808 *
13809 * SPEC XPath 1.0:
13810 * "only predicates change the context position and
13811 * context size (see [2.4 Predicates])."
13812 * Example:
13813 * node-set context pos
13814 * nA 1
13815 * nB 2
13816 * nC 3
13817 * After applying predicate [position() > 1] :
13818 * node-set context pos
13819 * nB 1
13820 * nC 2
13821 *
13822 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013823 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013824 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013825 for (i = 0; i < oldset->nodeNr; i++) {
13826 /*
13827 * Run the evaluation with a node list made of
13828 * a single item in the nodeset.
13829 */
13830 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013831 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13832 (oldset->nodeTab[i]->doc != NULL))
13833 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013834 if (tmp == NULL) {
13835 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13836 ctxt->context->node);
13837 } else {
13838 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13839 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013840 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013841 valuePush(ctxt, tmp);
13842 ctxt->context->contextSize = oldset->nodeNr;
13843 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013844 /*
13845 * Evaluate the predicate against the context node.
13846 * Can/should we optimize position() predicates
13847 * here (e.g. "[1]")?
13848 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013849 if (op->ch2 != -1)
13850 total +=
13851 xmlXPathCompOpEval(ctxt,
13852 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013853 if (ctxt->error != XPATH_EXPRESSION_OK) {
13854 xmlXPathFreeNodeSet(newset);
13855 xmlXPathFreeObject(obj);
13856 return(0);
13857 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013858
Daniel Veillardf06307e2001-07-03 10:35:50 +000013859 /*
William M. Brack08171912003-12-29 02:52:11 +000013860 * The result of the evaluation needs to be tested to
13861 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013862 */
13863 /*
13864 * OPTIMIZE TODO: Can we use
13865 * xmlXPathNodeSetAdd*Unique()* instead?
13866 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013867 res = valuePop(ctxt);
13868 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13869 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13870 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013871
Daniel Veillardf06307e2001-07-03 10:35:50 +000013872 /*
13873 * Cleanup
13874 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013875 if (res != NULL) {
13876 xmlXPathReleaseObject(ctxt->context, res);
13877 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013878 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013879 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013880 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013881 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013882 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013883 * in order to avoid massive recreation inside this
13884 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013885 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013886 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013887 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013888 ctxt->context->node = NULL;
13889 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013890 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013891 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013892 /*
13893 * The result is used as the new evaluation set.
13894 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013895 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013896 ctxt->context->node = NULL;
13897 ctxt->context->contextSize = -1;
13898 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013899 /* may want to move this past the '}' later */
13900 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013901 valuePush(ctxt,
13902 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013903 }
13904 ctxt->context->node = oldnode;
13905 return (total);
13906 }
13907 case XPATH_OP_SORT:
13908 if (op->ch1 != -1)
13909 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013910 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013911 if ((ctxt->value != NULL) &&
13912 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013913 (ctxt->value->nodesetval != NULL) &&
13914 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013915 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013916 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013917 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013918 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013919#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013920 case XPATH_OP_RANGETO:{
13921 xmlXPathObjectPtr range;
13922 xmlXPathObjectPtr res, obj;
13923 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013924 xmlLocationSetPtr newlocset = NULL;
13925 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013926 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013927 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013928
Daniel Veillardf06307e2001-07-03 10:35:50 +000013929 if (op->ch1 != -1)
13930 total +=
13931 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13932 if (op->ch2 == -1)
13933 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013934
William M. Brack08171912003-12-29 02:52:11 +000013935 if (ctxt->value->type == XPATH_LOCATIONSET) {
13936 /*
13937 * Extract the old locset, and then evaluate the result of the
13938 * expression for all the element in the locset. use it to grow
13939 * up a new locset.
13940 */
13941 CHECK_TYPE0(XPATH_LOCATIONSET);
13942 obj = valuePop(ctxt);
13943 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013944
William M. Brack08171912003-12-29 02:52:11 +000013945 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013946 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013947 ctxt->context->contextSize = 0;
13948 ctxt->context->proximityPosition = 0;
13949 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13950 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013951 if (res != NULL) {
13952 xmlXPathReleaseObject(ctxt->context, res);
13953 }
William M. Brack08171912003-12-29 02:52:11 +000013954 valuePush(ctxt, obj);
13955 CHECK_ERROR0;
13956 return (total);
13957 }
13958 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013959
William M. Brack08171912003-12-29 02:52:11 +000013960 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013961 /*
William M. Brack08171912003-12-29 02:52:11 +000013962 * Run the evaluation with a node list made of a
13963 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013964 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013965 ctxt->context->node = oldlocset->locTab[i]->user;
13966 ctxt->context->contextSize = oldlocset->locNr;
13967 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013968 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13969 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013970 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013971
Daniel Veillardf06307e2001-07-03 10:35:50 +000013972 if (op->ch2 != -1)
13973 total +=
13974 xmlXPathCompOpEval(ctxt,
13975 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013976 if (ctxt->error != XPATH_EXPRESSION_OK) {
13977 xmlXPathFreeObject(obj);
13978 return(0);
13979 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013980
Daniel Veillardf06307e2001-07-03 10:35:50 +000013981 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013982 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013983 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000013984 (xmlLocationSetPtr)res->user;
13985 for (j=0; j<rloc->locNr; j++) {
13986 range = xmlXPtrNewRange(
13987 oldlocset->locTab[i]->user,
13988 oldlocset->locTab[i]->index,
13989 rloc->locTab[j]->user2,
13990 rloc->locTab[j]->index2);
13991 if (range != NULL) {
13992 xmlXPtrLocationSetAdd(newlocset, range);
13993 }
13994 }
13995 } else {
13996 range = xmlXPtrNewRangeNodeObject(
13997 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13998 if (range != NULL) {
13999 xmlXPtrLocationSetAdd(newlocset,range);
14000 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014001 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014002
Daniel Veillardf06307e2001-07-03 10:35:50 +000014003 /*
14004 * Cleanup
14005 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014006 if (res != NULL) {
14007 xmlXPathReleaseObject(ctxt->context, res);
14008 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014009 if (ctxt->value == tmp) {
14010 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014011 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014012 }
14013
14014 ctxt->context->node = NULL;
14015 }
William M. Brack72ee48d2003-12-30 08:30:19 +000014016 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000014017 CHECK_TYPE0(XPATH_NODESET);
14018 obj = valuePop(ctxt);
14019 oldset = obj->nodesetval;
14020 ctxt->context->node = NULL;
14021
14022 newlocset = xmlXPtrLocationSetCreate(NULL);
14023
14024 if (oldset != NULL) {
14025 for (i = 0; i < oldset->nodeNr; i++) {
14026 /*
14027 * Run the evaluation with a node list made of a single item
14028 * in the nodeset.
14029 */
14030 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014031 /*
14032 * OPTIMIZE TODO: Avoid recreation for every iteration.
14033 */
14034 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14035 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000014036 valuePush(ctxt, tmp);
14037
14038 if (op->ch2 != -1)
14039 total +=
14040 xmlXPathCompOpEval(ctxt,
14041 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014042 if (ctxt->error != XPATH_EXPRESSION_OK) {
14043 xmlXPathFreeObject(obj);
14044 return(0);
14045 }
William M. Brack08171912003-12-29 02:52:11 +000014046
William M. Brack08171912003-12-29 02:52:11 +000014047 res = valuePop(ctxt);
14048 range =
14049 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14050 res);
14051 if (range != NULL) {
14052 xmlXPtrLocationSetAdd(newlocset, range);
14053 }
14054
14055 /*
14056 * Cleanup
14057 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014058 if (res != NULL) {
14059 xmlXPathReleaseObject(ctxt->context, res);
14060 }
William M. Brack08171912003-12-29 02:52:11 +000014061 if (ctxt->value == tmp) {
14062 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014063 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000014064 }
14065
14066 ctxt->context->node = NULL;
14067 }
14068 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014069 }
14070
14071 /*
14072 * The result is used as the new evaluation set.
14073 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014074 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014075 ctxt->context->node = NULL;
14076 ctxt->context->contextSize = -1;
14077 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000014078 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014079 return (total);
14080 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014081#endif /* LIBXML_XPTR_ENABLED */
14082 }
14083 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000014084 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080014085 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014086 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014087}
14088
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014089/**
14090 * xmlXPathCompOpEvalToBoolean:
14091 * @ctxt: the XPath parser context
14092 *
14093 * Evaluates if the expression evaluates to true.
14094 *
14095 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14096 */
14097static int
14098xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014099 xmlXPathStepOpPtr op,
14100 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014101{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014102 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014103
14104start:
14105 /* comp = ctxt->comp; */
14106 switch (op->op) {
14107 case XPATH_OP_END:
14108 return (0);
14109 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014110 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014111 if (isPredicate)
14112 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14113 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014114 case XPATH_OP_SORT:
14115 /*
14116 * We don't need sorting for boolean results. Skip this one.
14117 */
14118 if (op->ch1 != -1) {
14119 op = &ctxt->comp->steps[op->ch1];
14120 goto start;
14121 }
14122 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014123 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014124 if (op->ch1 == -1)
14125 return(0);
14126
14127 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14128 if (ctxt->error != XPATH_EXPRESSION_OK)
14129 return(-1);
14130
14131 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14132 if (ctxt->error != XPATH_EXPRESSION_OK)
14133 return(-1);
14134
14135 resObj = valuePop(ctxt);
14136 if (resObj == NULL)
14137 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014138 break;
14139 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014140 /*
14141 * Fallback to call xmlXPathCompOpEval().
14142 */
14143 xmlXPathCompOpEval(ctxt, op);
14144 if (ctxt->error != XPATH_EXPRESSION_OK)
14145 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014146
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014147 resObj = valuePop(ctxt);
14148 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014149 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014150 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014151 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014152
14153 if (resObj) {
14154 int res;
14155
14156 if (resObj->type == XPATH_BOOLEAN) {
14157 res = resObj->boolval;
14158 } else if (isPredicate) {
14159 /*
14160 * For predicates a result of type "number" is handled
14161 * differently:
14162 * SPEC XPath 1.0:
14163 * "If the result is a number, the result will be converted
14164 * to true if the number is equal to the context position
14165 * and will be converted to false otherwise;"
14166 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014167 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014168 } else {
14169 res = xmlXPathCastToBoolean(resObj);
14170 }
14171 xmlXPathReleaseObject(ctxt->context, resObj);
14172 return(res);
14173 }
14174
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014175 return(0);
14176}
14177
Daniel Veillard56de87e2005-02-16 00:22:29 +000014178#ifdef XPATH_STREAMING
14179/**
14180 * xmlXPathRunStreamEval:
14181 * @ctxt: the XPath parser context with the compiled expression
14182 *
14183 * Evaluate the Precompiled Streamable XPath expression in the given context.
14184 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014185static int
14186xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14187 xmlXPathObjectPtr *resultSeq, int toBool)
14188{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014189 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014190 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014191 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014192 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014193 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014194 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014195
14196 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014197
14198 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014199 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014200 max_depth = xmlPatternMaxDepth(comp);
14201 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014202 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014203 if (max_depth == -2)
14204 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014205 min_depth = xmlPatternMinDepth(comp);
14206 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014207 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014208 from_root = xmlPatternFromRoot(comp);
14209 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014210 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014211#if 0
14212 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14213#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014214
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014215 if (! toBool) {
14216 if (resultSeq == NULL)
14217 return(-1);
14218 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14219 if (*resultSeq == NULL)
14220 return(-1);
14221 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014222
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014223 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014224 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014225 */
14226 if (min_depth == 0) {
14227 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014228 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014229 if (toBool)
14230 return(1);
14231 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14232 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014233 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014234 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014235 if (toBool)
14236 return(1);
14237 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014238 }
14239 }
14240 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014241 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014242 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014243
Daniel Veillard56de87e2005-02-16 00:22:29 +000014244 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014245 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014246 } else if (ctxt->node != NULL) {
14247 switch (ctxt->node->type) {
14248 case XML_ELEMENT_NODE:
14249 case XML_DOCUMENT_NODE:
14250 case XML_DOCUMENT_FRAG_NODE:
14251 case XML_HTML_DOCUMENT_NODE:
14252#ifdef LIBXML_DOCB_ENABLED
14253 case XML_DOCB_DOCUMENT_NODE:
14254#endif
14255 cur = ctxt->node;
14256 break;
14257 case XML_ATTRIBUTE_NODE:
14258 case XML_TEXT_NODE:
14259 case XML_CDATA_SECTION_NODE:
14260 case XML_ENTITY_REF_NODE:
14261 case XML_ENTITY_NODE:
14262 case XML_PI_NODE:
14263 case XML_COMMENT_NODE:
14264 case XML_NOTATION_NODE:
14265 case XML_DTD_NODE:
14266 case XML_DOCUMENT_TYPE_NODE:
14267 case XML_ELEMENT_DECL:
14268 case XML_ATTRIBUTE_DECL:
14269 case XML_ENTITY_DECL:
14270 case XML_NAMESPACE_DECL:
14271 case XML_XINCLUDE_START:
14272 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014273 break;
14274 }
14275 limit = cur;
14276 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014277 if (cur == NULL) {
14278 return(0);
14279 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014280
14281 patstream = xmlPatternGetStreamCtxt(comp);
14282 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014283 /*
14284 * QUESTION TODO: Is this an error?
14285 */
14286 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014287 }
14288
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014289 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014290
Daniel Veillard56de87e2005-02-16 00:22:29 +000014291 if (from_root) {
14292 ret = xmlStreamPush(patstream, NULL, NULL);
14293 if (ret < 0) {
14294 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014295 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014296 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014297 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014298 }
14299 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014300 depth = 0;
14301 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014302next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014303 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014304 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014305
14306 switch (cur->type) {
14307 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014308 case XML_TEXT_NODE:
14309 case XML_CDATA_SECTION_NODE:
14310 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014311 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014312 if (cur->type == XML_ELEMENT_NODE) {
14313 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014314 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014315 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014316 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14317 else
14318 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014319
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014320 if (ret < 0) {
14321 /* NOP. */
14322 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014323 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014324 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014325 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014326 }
14327 if ((cur->children == NULL) || (depth >= max_depth)) {
14328 ret = xmlStreamPop(patstream);
14329 while (cur->next != NULL) {
14330 cur = cur->next;
14331 if ((cur->type != XML_ENTITY_DECL) &&
14332 (cur->type != XML_DTD_NODE))
14333 goto next_node;
14334 }
14335 }
14336 default:
14337 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014338 }
14339
Daniel Veillard56de87e2005-02-16 00:22:29 +000014340scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080014341 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014342 if ((cur->children != NULL) && (depth < max_depth)) {
14343 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014344 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014345 */
14346 if (cur->children->type != XML_ENTITY_DECL) {
14347 cur = cur->children;
14348 depth++;
14349 /*
14350 * Skip DTDs
14351 */
14352 if (cur->type != XML_DTD_NODE)
14353 continue;
14354 }
14355 }
14356
14357 if (cur == limit)
14358 break;
14359
14360 while (cur->next != NULL) {
14361 cur = cur->next;
14362 if ((cur->type != XML_ENTITY_DECL) &&
14363 (cur->type != XML_DTD_NODE))
14364 goto next_node;
14365 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014366
Daniel Veillard56de87e2005-02-16 00:22:29 +000014367 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014368 cur = cur->parent;
14369 depth--;
14370 if ((cur == NULL) || (cur == limit))
14371 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014372 if (cur->type == XML_ELEMENT_NODE) {
14373 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014374 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014375 ((cur->type == XML_TEXT_NODE) ||
14376 (cur->type == XML_CDATA_SECTION_NODE) ||
14377 (cur->type == XML_COMMENT_NODE) ||
14378 (cur->type == XML_PI_NODE)))
14379 {
14380 ret = xmlStreamPop(patstream);
14381 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014382 if (cur->next != NULL) {
14383 cur = cur->next;
14384 break;
14385 }
14386 } while (cur != NULL);
14387
14388 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014389
Daniel Veillard56de87e2005-02-16 00:22:29 +000014390done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014391
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014392#if 0
14393 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014394 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014395#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014396
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014397 if (patstream)
14398 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014399 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014400
14401return_1:
14402 if (patstream)
14403 xmlFreeStreamCtxt(patstream);
14404 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014405}
14406#endif /* XPATH_STREAMING */
14407
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014408/**
14409 * xmlXPathRunEval:
14410 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014411 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014412 *
14413 * Evaluate the Precompiled XPath expression in the given context.
14414 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014415static int
14416xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14417{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014418 xmlXPathCompExprPtr comp;
14419
14420 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014421 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014422
14423 if (ctxt->valueTab == NULL) {
14424 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014425 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014426 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14427 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014428 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014429 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014430 }
14431 ctxt->valueNr = 0;
14432 ctxt->valueMax = 10;
14433 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014434 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014435 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014436#ifdef XPATH_STREAMING
14437 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014438 int res;
14439
14440 if (toBool) {
14441 /*
14442 * Evaluation to boolean result.
14443 */
14444 res = xmlXPathRunStreamEval(ctxt->context,
14445 ctxt->comp->stream, NULL, 1);
14446 if (res != -1)
14447 return(res);
14448 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014449 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014450
14451 /*
14452 * Evaluation to a sequence.
14453 */
14454 res = xmlXPathRunStreamEval(ctxt->context,
14455 ctxt->comp->stream, &resObj, 0);
14456
14457 if ((res != -1) && (resObj != NULL)) {
14458 valuePush(ctxt, resObj);
14459 return(0);
14460 }
14461 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014462 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014463 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014464 /*
14465 * QUESTION TODO: This falls back to normal XPath evaluation
14466 * if res == -1. Is this intended?
14467 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014468 }
14469#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014470 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014471 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014472 xmlGenericError(xmlGenericErrorContext,
14473 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014474 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014475 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014476 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014477 return(xmlXPathCompOpEvalToBoolean(ctxt,
14478 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014479 else
14480 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14481
14482 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014483}
14484
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014485/************************************************************************
14486 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014487 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014488 * *
14489 ************************************************************************/
14490
14491/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014492 * xmlXPathEvalPredicate:
14493 * @ctxt: the XPath context
14494 * @res: the Predicate Expression evaluation result
14495 *
14496 * Evaluate a predicate result for the current node.
14497 * A PredicateExpr is evaluated by evaluating the Expr and converting
14498 * the result to a boolean. If the result is a number, the result will
14499 * be converted to true if the number is equal to the position of the
14500 * context node in the context node list (as returned by the position
14501 * function) and will be converted to false otherwise; if the result
14502 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014503 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014504 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014505 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014506 */
14507int
14508xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014509 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014510 switch (res->type) {
14511 case XPATH_BOOLEAN:
14512 return(res->boolval);
14513 case XPATH_NUMBER:
14514 return(res->floatval == ctxt->proximityPosition);
14515 case XPATH_NODESET:
14516 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014517 if (res->nodesetval == NULL)
14518 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014519 return(res->nodesetval->nodeNr != 0);
14520 case XPATH_STRING:
14521 return((res->stringval != NULL) &&
14522 (xmlStrlen(res->stringval) != 0));
14523 default:
14524 STRANGE
14525 }
14526 return(0);
14527}
14528
14529/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014530 * xmlXPathEvaluatePredicateResult:
14531 * @ctxt: the XPath Parser context
14532 * @res: the Predicate Expression evaluation result
14533 *
14534 * Evaluate a predicate result for the current node.
14535 * A PredicateExpr is evaluated by evaluating the Expr and converting
14536 * the result to a boolean. If the result is a number, the result will
14537 * be converted to true if the number is equal to the position of the
14538 * context node in the context node list (as returned by the position
14539 * function) and will be converted to false otherwise; if the result
14540 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014541 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014542 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014543 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014544 */
14545int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014546xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014547 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014548 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014549 switch (res->type) {
14550 case XPATH_BOOLEAN:
14551 return(res->boolval);
14552 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014553#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014554 return((res->floatval == ctxt->context->proximityPosition) &&
14555 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014556#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014557 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014558#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014559 case XPATH_NODESET:
14560 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014561 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014562 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014563 return(res->nodesetval->nodeNr != 0);
14564 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014565 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014566#ifdef LIBXML_XPTR_ENABLED
14567 case XPATH_LOCATIONSET:{
14568 xmlLocationSetPtr ptr = res->user;
14569 if (ptr == NULL)
14570 return(0);
14571 return (ptr->locNr != 0);
14572 }
14573#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014574 default:
14575 STRANGE
14576 }
14577 return(0);
14578}
14579
Daniel Veillard56de87e2005-02-16 00:22:29 +000014580#ifdef XPATH_STREAMING
14581/**
14582 * xmlXPathTryStreamCompile:
14583 * @ctxt: an XPath context
14584 * @str: the XPath expression
14585 *
14586 * Try to compile the XPath expression as a streamable subset.
14587 *
14588 * Returns the compiled expression or NULL if failed to compile.
14589 */
14590static xmlXPathCompExprPtr
14591xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14592 /*
14593 * Optimization: use streaming patterns when the XPath expression can
14594 * be compiled to a stream lookup
14595 */
14596 xmlPatternPtr stream;
14597 xmlXPathCompExprPtr comp;
14598 xmlDictPtr dict = NULL;
14599 const xmlChar **namespaces = NULL;
14600 xmlNsPtr ns;
14601 int i, j;
14602
14603 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14604 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014605 const xmlChar *tmp;
14606
14607 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014608 * We don't try to handle expressions using the verbose axis
14609 * specifiers ("::"), just the simplied form at this point.
14610 * Additionally, if there is no list of namespaces available and
14611 * there's a ":" in the expression, indicating a prefixed QName,
14612 * then we won't try to compile either. xmlPatterncompile() needs
14613 * to have a list of namespaces at compilation time in order to
14614 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014615 */
14616 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014617 if ((tmp != NULL) &&
14618 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014619 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014620
Daniel Veillard56de87e2005-02-16 00:22:29 +000014621 if (ctxt != NULL) {
14622 dict = ctxt->dict;
14623 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014624 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014625 if (namespaces == NULL) {
14626 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14627 return(NULL);
14628 }
14629 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14630 ns = ctxt->namespaces[j];
14631 namespaces[i++] = ns->href;
14632 namespaces[i++] = ns->prefix;
14633 }
14634 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014635 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014636 }
14637 }
14638
William M. Brackea152c02005-06-09 18:12:28 +000014639 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14640 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014641 if (namespaces != NULL) {
14642 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014643 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014644 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14645 comp = xmlXPathNewCompExpr();
14646 if (comp == NULL) {
14647 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14648 return(NULL);
14649 }
14650 comp->stream = stream;
14651 comp->dict = dict;
14652 if (comp->dict)
14653 xmlDictReference(comp->dict);
14654 return(comp);
14655 }
14656 xmlFreePattern(stream);
14657 }
14658 return(NULL);
14659}
14660#endif /* XPATH_STREAMING */
14661
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014662static void
Nick Wellnhofer62270532012-08-19 19:42:38 +020014663xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014664{
14665 /*
14666 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14667 * internal representation.
14668 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014669
Nick Wellnhofer62270532012-08-19 19:42:38 +020014670 if ((op->ch1 != -1) &&
14671 (op->op == XPATH_OP_COLLECT /* 11 */))
14672 {
14673 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14674
14675 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14676 ((xmlXPathAxisVal) prevop->value ==
14677 AXIS_DESCENDANT_OR_SELF) &&
14678 (prevop->ch2 == -1) &&
14679 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14680 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14681 {
14682 /*
14683 * This is a "descendant-or-self::node()" without predicates.
14684 * Try to eliminate it.
14685 */
14686
14687 switch ((xmlXPathAxisVal) op->value) {
14688 case AXIS_CHILD:
14689 case AXIS_DESCENDANT:
14690 /*
14691 * Convert "descendant-or-self::node()/child::" or
14692 * "descendant-or-self::node()/descendant::" to
14693 * "descendant::"
14694 */
14695 op->ch1 = prevop->ch1;
14696 op->value = AXIS_DESCENDANT;
14697 break;
14698 case AXIS_SELF:
14699 case AXIS_DESCENDANT_OR_SELF:
14700 /*
14701 * Convert "descendant-or-self::node()/self::" or
14702 * "descendant-or-self::node()/descendant-or-self::" to
14703 * to "descendant-or-self::"
14704 */
14705 op->ch1 = prevop->ch1;
14706 op->value = AXIS_DESCENDANT_OR_SELF;
14707 break;
14708 default:
14709 break;
14710 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014711 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014712 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014713
14714 /* Recurse */
14715 if (op->ch1 != -1)
14716 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014717 if (op->ch2 != -1)
Nick Wellnhofer62270532012-08-19 19:42:38 +020014718 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014719}
14720
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014721/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014722 * xmlXPathCtxtCompile:
14723 * @ctxt: an XPath context
14724 * @str: the XPath expression
14725 *
14726 * Compile an XPath expression
14727 *
14728 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14729 * the caller has to free the object.
14730 */
14731xmlXPathCompExprPtr
14732xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14733 xmlXPathParserContextPtr pctxt;
14734 xmlXPathCompExprPtr comp;
14735
Daniel Veillard56de87e2005-02-16 00:22:29 +000014736#ifdef XPATH_STREAMING
14737 comp = xmlXPathTryStreamCompile(ctxt, str);
14738 if (comp != NULL)
14739 return(comp);
14740#endif
14741
Daniel Veillard4773df22004-01-23 13:15:13 +000014742 xmlXPathInit();
14743
14744 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014745 if (pctxt == NULL)
14746 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014747 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014748
14749 if( pctxt->error != XPATH_EXPRESSION_OK )
14750 {
14751 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014752 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014753 }
14754
14755 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014756 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014757 * aleksey: in some cases this line prints *second* error message
14758 * (see bug #78858) and probably this should be fixed.
14759 * However, we are not sure that all error messages are printed
14760 * out in other places. It's not critical so we leave it as-is for now
14761 */
14762 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14763 comp = NULL;
14764 } else {
14765 comp = pctxt->comp;
14766 pctxt->comp = NULL;
14767 }
14768 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014769
Daniel Veillard4773df22004-01-23 13:15:13 +000014770 if (comp != NULL) {
14771 comp->expr = xmlStrdup(str);
14772#ifdef DEBUG_EVAL_COUNTS
14773 comp->string = xmlStrdup(str);
14774 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014775#endif
Nick Wellnhofer62270532012-08-19 19:42:38 +020014776 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14777 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014778 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014779 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014780 return(comp);
14781}
14782
14783/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014784 * xmlXPathCompile:
14785 * @str: the XPath expression
14786 *
14787 * Compile an XPath expression
14788 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014789 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014790 * the caller has to free the object.
14791 */
14792xmlXPathCompExprPtr
14793xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014794 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014795}
14796
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014797/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014798 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014799 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014800 * @ctxt: the XPath context
14801 * @resObj: the resulting XPath object or NULL
14802 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014803 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014804 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014805 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014806 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014807 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014808 * the caller has to free the object.
14809 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014810static int
14811xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14812 xmlXPathContextPtr ctxt,
14813 xmlXPathObjectPtr *resObj,
14814 int toBool)
14815{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014816 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014817#ifndef LIBXML_THREAD_ENABLED
14818 static int reentance = 0;
14819#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014820 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014821
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014822 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014823
14824 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014825 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014826 xmlXPathInit();
14827
Daniel Veillard81463942001-10-16 12:34:39 +000014828#ifndef LIBXML_THREAD_ENABLED
14829 reentance++;
14830 if (reentance > 1)
14831 xmlXPathDisableOptimizer = 1;
14832#endif
14833
Daniel Veillardf06307e2001-07-03 10:35:50 +000014834#ifdef DEBUG_EVAL_COUNTS
14835 comp->nb++;
14836 if ((comp->string != NULL) && (comp->nb > 100)) {
14837 fprintf(stderr, "100 x %s\n", comp->string);
14838 comp->nb = 0;
14839 }
14840#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014841 pctxt = xmlXPathCompParserContext(comp, ctxt);
14842 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014843
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014844 if (resObj) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014845 if (pctxt->value == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014846 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014847 "xmlXPathCompiledEval: evaluation failed\n");
Daniel Veillard45490ae2008-07-29 09:13:19 +000014848 *resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014849 } else {
14850 *resObj = valuePop(pctxt);
14851 }
Owen Taylor3473f882001-02-23 17:55:21 +000014852 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014853
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014854 /*
14855 * Pop all remaining objects from the stack.
14856 */
14857 if (pctxt->valueNr > 0) {
14858 xmlXPathObjectPtr tmp;
14859 int stack = 0;
14860
14861 do {
14862 tmp = valuePop(pctxt);
14863 if (tmp != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014864 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014865 xmlXPathReleaseObject(ctxt, tmp);
14866 }
14867 } while (tmp != NULL);
14868 if ((stack != 0) &&
14869 ((toBool) || ((resObj) && (*resObj))))
14870 {
14871 xmlGenericError(xmlGenericErrorContext,
14872 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14873 stack);
14874 }
Owen Taylor3473f882001-02-23 17:55:21 +000014875 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014876
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014877 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14878 xmlXPathFreeObject(*resObj);
14879 *resObj = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014880 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014881 pctxt->comp = NULL;
14882 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014883#ifndef LIBXML_THREAD_ENABLED
14884 reentance--;
14885#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014886
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014887 return(res);
14888}
14889
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014890/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014891 * xmlXPathCompiledEval:
14892 * @comp: the compiled XPath expression
14893 * @ctx: the XPath context
14894 *
14895 * Evaluate the Precompiled XPath expression in the given context.
14896 *
14897 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14898 * the caller has to free the object.
14899 */
14900xmlXPathObjectPtr
14901xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14902{
14903 xmlXPathObjectPtr res = NULL;
14904
14905 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14906 return(res);
14907}
14908
14909/**
14910 * xmlXPathCompiledEvalToBoolean:
14911 * @comp: the compiled XPath expression
14912 * @ctxt: the XPath context
14913 *
14914 * Applies the XPath boolean() function on the result of the given
14915 * compiled expression.
14916 *
14917 * Returns 1 if the expression evaluated to true, 0 if to false and
14918 * -1 in API and internal errors.
14919 */
14920int
14921xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14922 xmlXPathContextPtr ctxt)
14923{
14924 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14925}
14926
14927/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014928 * xmlXPathEvalExpr:
14929 * @ctxt: the XPath Parser context
14930 *
14931 * Parse and evaluate an XPath expression in the given context,
14932 * then push the result on the context stack
14933 */
14934void
14935xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014936#ifdef XPATH_STREAMING
14937 xmlXPathCompExprPtr comp;
14938#endif
14939
Daniel Veillarda82b1822004-11-08 16:24:57 +000014940 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014941
Daniel Veillard56de87e2005-02-16 00:22:29 +000014942#ifdef XPATH_STREAMING
14943 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14944 if (comp != NULL) {
14945 if (ctxt->comp != NULL)
14946 xmlXPathFreeCompExpr(ctxt->comp);
14947 ctxt->comp = comp;
14948 if (ctxt->cur != NULL)
14949 while (*ctxt->cur != 0) ctxt->cur++;
14950 } else
14951#endif
14952 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014953 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014954 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14955 (ctxt->comp != NULL) &&
Nick Wellnhofer62270532012-08-19 19:42:38 +020014956 (ctxt->comp->nbStep > 1) &&
14957 (ctxt->comp->last >= 0))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014958 {
Nick Wellnhofer62270532012-08-19 19:42:38 +020014959 xmlXPathOptimizeExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014960 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014961 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014962 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014963 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014964 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014965}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014966
14967/**
14968 * xmlXPathEval:
14969 * @str: the XPath expression
14970 * @ctx: the XPath context
14971 *
14972 * Evaluate the XPath Location Path in the given context.
14973 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014974 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014975 * the caller has to free the object.
14976 */
14977xmlXPathObjectPtr
14978xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14979 xmlXPathParserContextPtr ctxt;
14980 xmlXPathObjectPtr res, tmp, init = NULL;
14981 int stack = 0;
14982
William M. Brackf13f77f2004-11-12 16:03:48 +000014983 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014984
William M. Brackf13f77f2004-11-12 16:03:48 +000014985 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014986
14987 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014988 if (ctxt == NULL)
14989 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014990 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014991
14992 if (ctxt->value == NULL) {
14993 xmlGenericError(xmlGenericErrorContext,
14994 "xmlXPathEval: evaluation failed\n");
14995 res = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014996 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
Daniel Veillard56de87e2005-02-16 00:22:29 +000014997#ifdef XPATH_STREAMING
14998 && (ctxt->comp->stream == NULL)
14999#endif
15000 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015001 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15002 res = NULL;
15003 } else {
15004 res = valuePop(ctxt);
15005 }
15006
15007 do {
15008 tmp = valuePop(ctxt);
15009 if (tmp != NULL) {
15010 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015011 stack++;
15012 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015013 }
15014 } while (tmp != NULL);
15015 if ((stack != 0) && (res != NULL)) {
15016 xmlGenericError(xmlGenericErrorContext,
15017 "xmlXPathEval: %d object left on the stack\n",
15018 stack);
15019 }
15020 if (ctxt->error != XPATH_EXPRESSION_OK) {
15021 xmlXPathFreeObject(res);
15022 res = NULL;
15023 }
15024
Owen Taylor3473f882001-02-23 17:55:21 +000015025 xmlXPathFreeParserContext(ctxt);
15026 return(res);
15027}
15028
15029/**
15030 * xmlXPathEvalExpression:
15031 * @str: the XPath expression
15032 * @ctxt: the XPath context
15033 *
15034 * Evaluate the XPath expression in the given context.
15035 *
15036 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15037 * the caller has to free the object.
15038 */
15039xmlXPathObjectPtr
15040xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15041 xmlXPathParserContextPtr pctxt;
15042 xmlXPathObjectPtr res, tmp;
15043 int stack = 0;
15044
William M. Brackf13f77f2004-11-12 16:03:48 +000015045 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000015046
William M. Brackf13f77f2004-11-12 16:03:48 +000015047 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000015048
15049 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000015050 if (pctxt == NULL)
15051 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000015052 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000015053
Daniel Veillardc465ffc2006-10-17 19:39:33 +000015054 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000015055 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15056 res = NULL;
15057 } else {
15058 res = valuePop(pctxt);
15059 }
15060 do {
15061 tmp = valuePop(pctxt);
15062 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015063 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000015064 stack++;
15065 }
15066 } while (tmp != NULL);
15067 if ((stack != 0) && (res != NULL)) {
15068 xmlGenericError(xmlGenericErrorContext,
15069 "xmlXPathEvalExpression: %d object left on the stack\n",
15070 stack);
15071 }
15072 xmlXPathFreeParserContext(pctxt);
15073 return(res);
15074}
15075
Daniel Veillard42766c02002-08-22 20:52:17 +000015076/************************************************************************
15077 * *
15078 * Extra functions not pertaining to the XPath spec *
15079 * *
15080 ************************************************************************/
15081/**
15082 * xmlXPathEscapeUriFunction:
15083 * @ctxt: the XPath Parser context
15084 * @nargs: the number of arguments
15085 *
15086 * Implement the escape-uri() XPath function
15087 * string escape-uri(string $str, bool $escape-reserved)
15088 *
15089 * This function applies the URI escaping rules defined in section 2 of [RFC
15090 * 2396] to the string supplied as $uri-part, which typically represents all
15091 * or part of a URI. The effect of the function is to replace any special
15092 * character in the string by an escape sequence of the form %xx%yy...,
15093 * where xxyy... is the hexadecimal representation of the octets used to
15094 * represent the character in UTF-8.
15095 *
15096 * The set of characters that are escaped depends on the setting of the
15097 * boolean argument $escape-reserved.
15098 *
15099 * If $escape-reserved is true, all characters are escaped other than lower
15100 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15101 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15102 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15103 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15104 * A-F).
15105 *
15106 * If $escape-reserved is false, the behavior differs in that characters
15107 * referred to in [RFC 2396] as reserved characters are not escaped. These
15108 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015109 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015110 * [RFC 2396] does not define whether escaped URIs should use lower case or
15111 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15112 * compared using string comparison functions, this function must always use
15113 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015114 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015115 * Generally, $escape-reserved should be set to true when escaping a string
15116 * that is to form a single part of a URI, and to false when escaping an
15117 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015118 *
15119 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015120 * utf-8 and then converted according to RFC 2396.
15121 *
15122 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015123 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015124 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15125 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15126 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15127 *
15128 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015129static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015130xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15131 xmlXPathObjectPtr str;
15132 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080015133 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000015134 xmlChar *cptr;
15135 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015136
Daniel Veillard42766c02002-08-22 20:52:17 +000015137 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015138
Daniel Veillard42766c02002-08-22 20:52:17 +000015139 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015140
Daniel Veillard42766c02002-08-22 20:52:17 +000015141 CAST_TO_STRING;
15142 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015143
Daniel Veillardade10f22012-07-12 09:43:27 +080015144 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015145
Daniel Veillard42766c02002-08-22 20:52:17 +000015146 escape[0] = '%';
15147 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015148
Daniel Veillard42766c02002-08-22 20:52:17 +000015149 if (target) {
15150 for (cptr = str->stringval; *cptr; cptr++) {
15151 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15152 (*cptr >= 'a' && *cptr <= 'z') ||
15153 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015154 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015155 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15156 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015157 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015158 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15159 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15160 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15161 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15162 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15163 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15164 (!escape_reserved &&
15165 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15166 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15167 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15168 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080015169 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000015170 } else {
15171 if ((*cptr >> 4) < 10)
15172 escape[1] = '0' + (*cptr >> 4);
15173 else
15174 escape[1] = 'A' - 10 + (*cptr >> 4);
15175 if ((*cptr & 0xF) < 10)
15176 escape[2] = '0' + (*cptr & 0xF);
15177 else
15178 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015179
Daniel Veillardade10f22012-07-12 09:43:27 +080015180 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000015181 }
15182 }
15183 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015184 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080015185 xmlBufContent(target)));
15186 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015187 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015188}
15189
Owen Taylor3473f882001-02-23 17:55:21 +000015190/**
15191 * xmlXPathRegisterAllFunctions:
15192 * @ctxt: the XPath context
15193 *
15194 * Registers all default XPath functions in this context
15195 */
15196void
15197xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15198{
15199 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15200 xmlXPathBooleanFunction);
15201 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15202 xmlXPathCeilingFunction);
15203 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15204 xmlXPathCountFunction);
15205 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15206 xmlXPathConcatFunction);
15207 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15208 xmlXPathContainsFunction);
15209 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15210 xmlXPathIdFunction);
15211 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15212 xmlXPathFalseFunction);
15213 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15214 xmlXPathFloorFunction);
15215 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15216 xmlXPathLastFunction);
15217 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15218 xmlXPathLangFunction);
15219 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15220 xmlXPathLocalNameFunction);
15221 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15222 xmlXPathNotFunction);
15223 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15224 xmlXPathNameFunction);
15225 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15226 xmlXPathNamespaceURIFunction);
15227 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15228 xmlXPathNormalizeFunction);
15229 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15230 xmlXPathNumberFunction);
15231 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15232 xmlXPathPositionFunction);
15233 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15234 xmlXPathRoundFunction);
15235 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15236 xmlXPathStringFunction);
15237 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15238 xmlXPathStringLengthFunction);
15239 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15240 xmlXPathStartsWithFunction);
15241 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15242 xmlXPathSubstringFunction);
15243 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15244 xmlXPathSubstringBeforeFunction);
15245 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15246 xmlXPathSubstringAfterFunction);
15247 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15248 xmlXPathSumFunction);
15249 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15250 xmlXPathTrueFunction);
15251 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15252 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015253
15254 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15255 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15256 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015257}
15258
15259#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015260#define bottom_xpath
15261#include "elfgcchack.h"