blob: c3236ed361dd1040cb126f766b40bf9e218c1021 [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",
Daniel Veillard47881282012-09-07 14:24:50 +0800331 "Forbidden variable\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000332 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000333};
William M. Brackcd65bc92005-01-06 09:39:18 +0000334#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
335 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000336/**
337 * xmlXPathErrMemory:
338 * @ctxt: an XPath context
339 * @extra: extra informations
340 *
341 * Handle a redefinition of attribute error
342 */
343static void
344xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
345{
346 if (ctxt != NULL) {
347 if (extra) {
348 xmlChar buf[200];
349
350 xmlStrPrintf(buf, 200,
351 BAD_CAST "Memory allocation failed : %s\n",
352 extra);
353 ctxt->lastError.message = (char *) xmlStrdup(buf);
354 } else {
355 ctxt->lastError.message = (char *)
356 xmlStrdup(BAD_CAST "Memory allocation failed\n");
357 }
358 ctxt->lastError.domain = XML_FROM_XPATH;
359 ctxt->lastError.code = XML_ERR_NO_MEMORY;
360 if (ctxt->error != NULL)
361 ctxt->error(ctxt->userData, &ctxt->lastError);
362 } else {
363 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000364 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000365 NULL, NULL, XML_FROM_XPATH,
366 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
367 extra, NULL, NULL, 0, 0,
368 "Memory allocation failed : %s\n", extra);
369 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000370 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000371 NULL, NULL, XML_FROM_XPATH,
372 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
373 NULL, NULL, NULL, 0, 0,
374 "Memory allocation failed\n");
375 }
376}
377
378/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000379 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000380 * @ctxt: an XPath parser context
381 * @extra: extra informations
382 *
383 * Handle a redefinition of attribute error
384 */
385static void
386xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
387{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000388 if (ctxt == NULL)
389 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000390 else {
391 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000392 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000393 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000394}
395
396/**
397 * xmlXPathErr:
398 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000399 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000400 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000401 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000402 */
403void
404xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
405{
William M. Brackcd65bc92005-01-06 09:39:18 +0000406 if ((error < 0) || (error > MAXERRNO))
407 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000408 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000409 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000410 NULL, NULL, XML_FROM_XPATH,
411 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
412 XML_ERR_ERROR, NULL, 0,
413 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200414 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000415 return;
416 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000417 ctxt->error = error;
418 if (ctxt->context == NULL) {
419 __xmlRaiseError(NULL, NULL, NULL,
420 NULL, NULL, XML_FROM_XPATH,
421 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
422 XML_ERR_ERROR, NULL, 0,
423 (const char *) ctxt->base, NULL, NULL,
424 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200425 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000426 return;
427 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000428
429 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000430 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000431
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000432 ctxt->context->lastError.domain = XML_FROM_XPATH;
433 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
434 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000435 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000436 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
437 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
438 ctxt->context->lastError.node = ctxt->context->debugNode;
439 if (ctxt->context->error != NULL) {
440 ctxt->context->error(ctxt->context->userData,
441 &ctxt->context->lastError);
442 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000443 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000444 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
445 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
446 XML_ERR_ERROR, NULL, 0,
447 (const char *) ctxt->base, NULL, NULL,
448 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200449 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000450 }
451
452}
453
454/**
455 * xmlXPatherror:
456 * @ctxt: the XPath Parser context
457 * @file: the file name
458 * @line: the line number
459 * @no: the error number
460 *
461 * Formats an error message.
462 */
463void
464xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
465 int line ATTRIBUTE_UNUSED, int no) {
466 xmlXPathErr(ctxt, no);
467}
468
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000469/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000470 * *
471 * Utilities *
472 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000473 ************************************************************************/
474
475/**
476 * xsltPointerList:
477 *
478 * Pointer-list for various purposes.
479 */
480typedef struct _xmlPointerList xmlPointerList;
481typedef xmlPointerList *xmlPointerListPtr;
482struct _xmlPointerList {
483 void **items;
484 int number;
485 int size;
486};
487/*
488* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
489* and here, we should make the functions public.
490*/
491static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000492xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000493 void *item,
494 int initialSize)
495{
496 if (list->items == NULL) {
497 if (initialSize <= 0)
498 initialSize = 1;
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800499 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000500 if (list->items == NULL) {
501 xmlXPathErrMemory(NULL,
502 "xmlPointerListCreate: allocating item\n");
503 return(-1);
504 }
505 list->number = 0;
506 list->size = initialSize;
507 } else if (list->size <= list->number) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800508 if (list->size > 50000000) {
509 xmlXPathErrMemory(NULL,
510 "xmlPointerListAddSize: re-allocating item\n");
511 return(-1);
512 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000513 list->size *= 2;
514 list->items = (void **) xmlRealloc(list->items,
515 list->size * sizeof(void *));
516 if (list->items == NULL) {
517 xmlXPathErrMemory(NULL,
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800518 "xmlPointerListAddSize: re-allocating item\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000519 list->size = 0;
520 return(-1);
521 }
522 }
523 list->items[list->number++] = item;
524 return(0);
525}
526
527/**
528 * xsltPointerListCreate:
529 *
530 * Creates an xsltPointerList structure.
531 *
532 * Returns a xsltPointerList structure or NULL in case of an error.
533 */
534static xmlPointerListPtr
535xmlPointerListCreate(int initialSize)
536{
537 xmlPointerListPtr ret;
538
539 ret = xmlMalloc(sizeof(xmlPointerList));
540 if (ret == NULL) {
541 xmlXPathErrMemory(NULL,
542 "xmlPointerListCreate: allocating item\n");
543 return (NULL);
544 }
545 memset(ret, 0, sizeof(xmlPointerList));
546 if (initialSize > 0) {
547 xmlPointerListAddSize(ret, NULL, initialSize);
548 ret->number = 0;
549 }
550 return (ret);
551}
552
553/**
554 * xsltPointerListFree:
555 *
556 * Frees the xsltPointerList structure. This does not free
557 * the content of the list.
558 */
559static void
560xmlPointerListFree(xmlPointerListPtr list)
561{
562 if (list == NULL)
563 return;
564 if (list->items != NULL)
565 xmlFree(list->items);
566 xmlFree(list);
567}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000568
569/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000570 * *
571 * Parser Types *
572 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000573 ************************************************************************/
574
575/*
576 * Types are private:
577 */
578
579typedef enum {
580 XPATH_OP_END=0,
581 XPATH_OP_AND,
582 XPATH_OP_OR,
583 XPATH_OP_EQUAL,
584 XPATH_OP_CMP,
585 XPATH_OP_PLUS,
586 XPATH_OP_MULT,
587 XPATH_OP_UNION,
588 XPATH_OP_ROOT,
589 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000590 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000591 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000592 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000593 XPATH_OP_VARIABLE,
594 XPATH_OP_FUNCTION,
595 XPATH_OP_ARG,
596 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000597 XPATH_OP_FILTER, /* 17 */
598 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000599#ifdef LIBXML_XPTR_ENABLED
600 ,XPATH_OP_RANGETO
601#endif
602} xmlXPathOp;
603
604typedef enum {
605 AXIS_ANCESTOR = 1,
606 AXIS_ANCESTOR_OR_SELF,
607 AXIS_ATTRIBUTE,
608 AXIS_CHILD,
609 AXIS_DESCENDANT,
610 AXIS_DESCENDANT_OR_SELF,
611 AXIS_FOLLOWING,
612 AXIS_FOLLOWING_SIBLING,
613 AXIS_NAMESPACE,
614 AXIS_PARENT,
615 AXIS_PRECEDING,
616 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000617 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000618} xmlXPathAxisVal;
619
620typedef enum {
621 NODE_TEST_NONE = 0,
622 NODE_TEST_TYPE = 1,
623 NODE_TEST_PI = 2,
624 NODE_TEST_ALL = 3,
625 NODE_TEST_NS = 4,
626 NODE_TEST_NAME = 5
627} xmlXPathTestVal;
628
629typedef enum {
630 NODE_TYPE_NODE = 0,
631 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
632 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000633 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000634} xmlXPathTypeVal;
635
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000636typedef struct _xmlXPathStepOp xmlXPathStepOp;
637typedef xmlXPathStepOp *xmlXPathStepOpPtr;
638struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000639 xmlXPathOp op; /* The identifier of the operation */
640 int ch1; /* First child */
641 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000642 int value;
643 int value2;
644 int value3;
645 void *value4;
646 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000647 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000648 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000649};
650
651struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000652 int nbStep; /* Number of steps in this expression */
653 int maxStep; /* Maximum number of steps allocated */
654 xmlXPathStepOp *steps; /* ops for computation of this expression */
655 int last; /* index of last step in expression */
656 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000657 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000658#ifdef DEBUG_EVAL_COUNTS
659 int nb;
660 xmlChar *string;
661#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000662#ifdef XPATH_STREAMING
663 xmlPatternPtr stream;
664#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000665};
666
667/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000668 * *
669 * Forward declarations *
670 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000671 ************************************************************************/
672static void
673xmlXPathFreeValueTree(xmlNodeSetPtr obj);
674static void
675xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
676static int
677xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
678 xmlXPathStepOpPtr op, xmlNodePtr *first);
679static int
680xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000681 xmlXPathStepOpPtr op,
682 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000683
684/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000685 * *
686 * Parser Type functions *
687 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000688 ************************************************************************/
689
690/**
691 * xmlXPathNewCompExpr:
692 *
693 * Create a new Xpath component
694 *
695 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
696 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000697static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000698xmlXPathNewCompExpr(void) {
699 xmlXPathCompExprPtr cur;
700
701 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
702 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000703 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000704 return(NULL);
705 }
706 memset(cur, 0, sizeof(xmlXPathCompExpr));
707 cur->maxStep = 10;
708 cur->nbStep = 0;
709 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
710 sizeof(xmlXPathStepOp));
711 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000712 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000713 xmlFree(cur);
714 return(NULL);
715 }
716 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
717 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000718#ifdef DEBUG_EVAL_COUNTS
719 cur->nb = 0;
720#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000721 return(cur);
722}
723
724/**
725 * xmlXPathFreeCompExpr:
726 * @comp: an XPATH comp
727 *
728 * Free up the memory allocated by @comp
729 */
730void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000731xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
732{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000733 xmlXPathStepOpPtr op;
734 int i;
735
736 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000737 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000738 if (comp->dict == NULL) {
739 for (i = 0; i < comp->nbStep; i++) {
740 op = &comp->steps[i];
741 if (op->value4 != NULL) {
742 if (op->op == XPATH_OP_VALUE)
743 xmlXPathFreeObject(op->value4);
744 else
745 xmlFree(op->value4);
746 }
747 if (op->value5 != NULL)
748 xmlFree(op->value5);
749 }
750 } else {
751 for (i = 0; i < comp->nbStep; i++) {
752 op = &comp->steps[i];
753 if (op->value4 != NULL) {
754 if (op->op == XPATH_OP_VALUE)
755 xmlXPathFreeObject(op->value4);
756 }
757 }
758 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000759 }
760 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000761 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000762 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000763#ifdef DEBUG_EVAL_COUNTS
764 if (comp->string != NULL) {
765 xmlFree(comp->string);
766 }
767#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000768#ifdef XPATH_STREAMING
769 if (comp->stream != NULL) {
770 xmlFreePatternList(comp->stream);
771 }
772#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000773 if (comp->expr != NULL) {
774 xmlFree(comp->expr);
775 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000776
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000777 xmlFree(comp);
778}
779
780/**
781 * xmlXPathCompExprAdd:
782 * @comp: the compiled expression
783 * @ch1: first child index
784 * @ch2: second child index
785 * @op: an op
786 * @value: the first int value
787 * @value2: the second int value
788 * @value3: the third int value
789 * @value4: the first string value
790 * @value5: the second string value
791 *
William M. Brack08171912003-12-29 02:52:11 +0000792 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000793 *
794 * Returns -1 in case of failure, the index otherwise
795 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000796static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000797xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
798 xmlXPathOp op, int value,
799 int value2, int value3, void *value4, void *value5) {
800 if (comp->nbStep >= comp->maxStep) {
801 xmlXPathStepOp *real;
802
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800803 if (comp->maxStep >= XPATH_MAX_STEPS) {
804 xmlXPathErrMemory(NULL, "adding step\n");
805 return(-1);
806 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000807 comp->maxStep *= 2;
808 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
809 comp->maxStep * sizeof(xmlXPathStepOp));
810 if (real == NULL) {
811 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000812 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000813 return(-1);
814 }
815 comp->steps = real;
816 }
817 comp->last = comp->nbStep;
818 comp->steps[comp->nbStep].ch1 = ch1;
819 comp->steps[comp->nbStep].ch2 = ch2;
820 comp->steps[comp->nbStep].op = op;
821 comp->steps[comp->nbStep].value = value;
822 comp->steps[comp->nbStep].value2 = value2;
823 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000824 if ((comp->dict != NULL) &&
825 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
826 (op == XPATH_OP_COLLECT))) {
827 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000828 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000829 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000830 xmlFree(value4);
831 } else
832 comp->steps[comp->nbStep].value4 = NULL;
833 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000834 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000835 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000836 xmlFree(value5);
837 } else
838 comp->steps[comp->nbStep].value5 = NULL;
839 } else {
840 comp->steps[comp->nbStep].value4 = value4;
841 comp->steps[comp->nbStep].value5 = value5;
842 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000843 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000844 return(comp->nbStep++);
845}
846
Daniel Veillardf06307e2001-07-03 10:35:50 +0000847/**
848 * xmlXPathCompSwap:
849 * @comp: the compiled expression
850 * @op: operation index
851 *
852 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000853 */
854static void
855xmlXPathCompSwap(xmlXPathStepOpPtr op) {
856 int tmp;
857
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000858#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000859 /*
860 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000861 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000862 * application
863 */
864 if (xmlXPathDisableOptimizer)
865 return;
866#endif
867
Daniel Veillardf06307e2001-07-03 10:35:50 +0000868 tmp = op->ch1;
869 op->ch1 = op->ch2;
870 op->ch2 = tmp;
871}
872
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000873#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
874 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
875 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000876#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
877 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
878 (op), (val), (val2), (val3), (val4), (val5))
879
Daniel Veillard45490ae2008-07-29 09:13:19 +0000880#define PUSH_LEAVE_EXPR(op, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000881xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
882
Daniel Veillard45490ae2008-07-29 09:13:19 +0000883#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000884xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
885
Daniel Veillard45490ae2008-07-29 09:13:19 +0000886#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000887xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
888 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000889
890/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000891 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000892 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000893 * *
894 ************************************************************************/
895
896/* #define XP_DEFAULT_CACHE_ON */
897
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000898#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000899
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000900typedef struct _xmlXPathContextCache xmlXPathContextCache;
901typedef xmlXPathContextCache *xmlXPathContextCachePtr;
902struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000903 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
904 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
905 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
906 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
907 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000908 int maxNodeset;
909 int maxString;
910 int maxBoolean;
911 int maxNumber;
912 int maxMisc;
913#ifdef XP_DEBUG_OBJ_USAGE
914 int dbgCachedAll;
915 int dbgCachedNodeset;
916 int dbgCachedString;
917 int dbgCachedBool;
918 int dbgCachedNumber;
919 int dbgCachedPoint;
920 int dbgCachedRange;
921 int dbgCachedLocset;
922 int dbgCachedUsers;
923 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000924 int dbgCachedUndefined;
925
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000926
927 int dbgReusedAll;
928 int dbgReusedNodeset;
929 int dbgReusedString;
930 int dbgReusedBool;
931 int dbgReusedNumber;
932 int dbgReusedPoint;
933 int dbgReusedRange;
934 int dbgReusedLocset;
935 int dbgReusedUsers;
936 int dbgReusedXSLTTree;
937 int dbgReusedUndefined;
938
939#endif
940};
941
942/************************************************************************
943 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000944 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +0000945 * *
946 ************************************************************************/
947
Daniel Veillard45490ae2008-07-29 09:13:19 +0000948#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +0000949 xmlGenericError(xmlGenericErrorContext, \
950 "Internal error at %s:%d\n", \
951 __FILE__, __LINE__);
952
953#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000954static void
955xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000956 int i;
957 char shift[100];
958
959 for (i = 0;((i < depth) && (i < 25));i++)
960 shift[2 * i] = shift[2 * i + 1] = ' ';
961 shift[2 * i] = shift[2 * i + 1] = 0;
962 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200963 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000964 fprintf(output, "Node is NULL !\n");
965 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000966
Owen Taylor3473f882001-02-23 17:55:21 +0000967 }
968
969 if ((cur->type == XML_DOCUMENT_NODE) ||
970 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200971 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000972 fprintf(output, " /\n");
973 } else if (cur->type == XML_ATTRIBUTE_NODE)
974 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
975 else
976 xmlDebugDumpOneNode(output, cur, depth);
977}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000978static void
979xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000980 xmlNodePtr tmp;
981 int i;
982 char shift[100];
983
984 for (i = 0;((i < depth) && (i < 25));i++)
985 shift[2 * i] = shift[2 * i + 1] = ' ';
986 shift[2 * i] = shift[2 * i + 1] = 0;
987 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200988 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000989 fprintf(output, "Node is NULL !\n");
990 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000991
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000992 }
993
994 while (cur != NULL) {
995 tmp = cur;
996 cur = cur->next;
997 xmlDebugDumpOneNode(output, tmp, depth);
998 }
999}
Owen Taylor3473f882001-02-23 17:55:21 +00001000
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001001static void
1002xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001003 int i;
1004 char shift[100];
1005
1006 for (i = 0;((i < depth) && (i < 25));i++)
1007 shift[2 * i] = shift[2 * i + 1] = ' ';
1008 shift[2 * i] = shift[2 * i + 1] = 0;
1009
1010 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001011 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001012 fprintf(output, "NodeSet is NULL !\n");
1013 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001014
Owen Taylor3473f882001-02-23 17:55:21 +00001015 }
1016
Daniel Veillard911f49a2001-04-07 15:39:35 +00001017 if (cur != NULL) {
1018 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1019 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001020 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +00001021 fprintf(output, "%d", i + 1);
1022 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1023 }
Owen Taylor3473f882001-02-23 17:55:21 +00001024 }
1025}
1026
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001027static void
1028xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001029 int i;
1030 char shift[100];
1031
1032 for (i = 0;((i < depth) && (i < 25));i++)
1033 shift[2 * i] = shift[2 * i + 1] = ' ';
1034 shift[2 * i] = shift[2 * i + 1] = 0;
1035
1036 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001037 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001038 fprintf(output, "Value Tree is NULL !\n");
1039 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001040
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001041 }
1042
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001043 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001044 fprintf(output, "%d", i + 1);
1045 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1046}
Owen Taylor3473f882001-02-23 17:55:21 +00001047#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001048static void
1049xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001050 int i;
1051 char shift[100];
1052
1053 for (i = 0;((i < depth) && (i < 25));i++)
1054 shift[2 * i] = shift[2 * i + 1] = ' ';
1055 shift[2 * i] = shift[2 * i + 1] = 0;
1056
1057 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001058 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001059 fprintf(output, "LocationSet is NULL !\n");
1060 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001061
Owen Taylor3473f882001-02-23 17:55:21 +00001062 }
1063
1064 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001065 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001066 fprintf(output, "%d : ", i + 1);
1067 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1068 }
1069}
Daniel Veillard017b1082001-06-21 11:20:21 +00001070#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001071
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00001072/**
1073 * xmlXPathDebugDumpObject:
1074 * @output: the FILE * to dump the output
1075 * @cur: the object to inspect
1076 * @depth: indentation level
1077 *
1078 * Dump the content of the object for debugging purposes
1079 */
1080void
1081xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001082 int i;
1083 char shift[100];
1084
Daniel Veillarda82b1822004-11-08 16:24:57 +00001085 if (output == NULL) return;
1086
Owen Taylor3473f882001-02-23 17:55:21 +00001087 for (i = 0;((i < depth) && (i < 25));i++)
1088 shift[2 * i] = shift[2 * i + 1] = ' ';
1089 shift[2 * i] = shift[2 * i + 1] = 0;
1090
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001091
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001092 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001093
1094 if (cur == NULL) {
1095 fprintf(output, "Object is empty (NULL)\n");
1096 return;
1097 }
1098 switch(cur->type) {
1099 case XPATH_UNDEFINED:
1100 fprintf(output, "Object is uninitialized\n");
1101 break;
1102 case XPATH_NODESET:
1103 fprintf(output, "Object is a Node Set :\n");
1104 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1105 break;
1106 case XPATH_XSLT_TREE:
1107 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001108 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001109 break;
1110 case XPATH_BOOLEAN:
1111 fprintf(output, "Object is a Boolean : ");
1112 if (cur->boolval) fprintf(output, "true\n");
1113 else fprintf(output, "false\n");
1114 break;
1115 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001116 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001117 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001118 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001119 break;
1120 case -1:
1121 fprintf(output, "Object is a number : -Infinity\n");
1122 break;
1123 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001124 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001125 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001126 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1127 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001128 } else {
1129 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1130 }
1131 }
Owen Taylor3473f882001-02-23 17:55:21 +00001132 break;
1133 case XPATH_STRING:
1134 fprintf(output, "Object is a string : ");
1135 xmlDebugDumpString(output, cur->stringval);
1136 fprintf(output, "\n");
1137 break;
1138 case XPATH_POINT:
1139 fprintf(output, "Object is a point : index %d in node", cur->index);
1140 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1141 fprintf(output, "\n");
1142 break;
1143 case XPATH_RANGE:
1144 if ((cur->user2 == NULL) ||
1145 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1146 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001147 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001148 if (cur->index >= 0)
1149 fprintf(output, "index %d in ", cur->index);
1150 fprintf(output, "node\n");
1151 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1152 depth + 1);
1153 } else {
1154 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001155 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001156 fprintf(output, "From ");
1157 if (cur->index >= 0)
1158 fprintf(output, "index %d in ", cur->index);
1159 fprintf(output, "node\n");
1160 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1161 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001162 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001163 fprintf(output, "To ");
1164 if (cur->index2 >= 0)
1165 fprintf(output, "index %d in ", cur->index2);
1166 fprintf(output, "node\n");
1167 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1168 depth + 1);
1169 fprintf(output, "\n");
1170 }
1171 break;
1172 case XPATH_LOCATIONSET:
1173#if defined(LIBXML_XPTR_ENABLED)
1174 fprintf(output, "Object is a Location Set:\n");
1175 xmlXPathDebugDumpLocationSet(output,
1176 (xmlLocationSetPtr) cur->user, depth);
1177#endif
1178 break;
1179 case XPATH_USERS:
1180 fprintf(output, "Object is user defined\n");
1181 break;
1182 }
1183}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001184
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001185static void
1186xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001187 xmlXPathStepOpPtr op, int depth) {
1188 int i;
1189 char shift[100];
1190
1191 for (i = 0;((i < depth) && (i < 25));i++)
1192 shift[2 * i] = shift[2 * i + 1] = ' ';
1193 shift[2 * i] = shift[2 * i + 1] = 0;
1194
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001195 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001196 if (op == NULL) {
1197 fprintf(output, "Step is NULL\n");
1198 return;
1199 }
1200 switch (op->op) {
1201 case XPATH_OP_END:
1202 fprintf(output, "END"); break;
1203 case XPATH_OP_AND:
1204 fprintf(output, "AND"); break;
1205 case XPATH_OP_OR:
1206 fprintf(output, "OR"); break;
1207 case XPATH_OP_EQUAL:
1208 if (op->value)
1209 fprintf(output, "EQUAL =");
1210 else
1211 fprintf(output, "EQUAL !=");
1212 break;
1213 case XPATH_OP_CMP:
1214 if (op->value)
1215 fprintf(output, "CMP <");
1216 else
1217 fprintf(output, "CMP >");
1218 if (!op->value2)
1219 fprintf(output, "=");
1220 break;
1221 case XPATH_OP_PLUS:
1222 if (op->value == 0)
1223 fprintf(output, "PLUS -");
1224 else if (op->value == 1)
1225 fprintf(output, "PLUS +");
1226 else if (op->value == 2)
1227 fprintf(output, "PLUS unary -");
1228 else if (op->value == 3)
1229 fprintf(output, "PLUS unary - -");
1230 break;
1231 case XPATH_OP_MULT:
1232 if (op->value == 0)
1233 fprintf(output, "MULT *");
1234 else if (op->value == 1)
1235 fprintf(output, "MULT div");
1236 else
1237 fprintf(output, "MULT mod");
1238 break;
1239 case XPATH_OP_UNION:
1240 fprintf(output, "UNION"); break;
1241 case XPATH_OP_ROOT:
1242 fprintf(output, "ROOT"); break;
1243 case XPATH_OP_NODE:
1244 fprintf(output, "NODE"); break;
1245 case XPATH_OP_RESET:
1246 fprintf(output, "RESET"); break;
1247 case XPATH_OP_SORT:
1248 fprintf(output, "SORT"); break;
1249 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001250 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1251 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1252 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001253 const xmlChar *prefix = op->value4;
1254 const xmlChar *name = op->value5;
1255
1256 fprintf(output, "COLLECT ");
1257 switch (axis) {
1258 case AXIS_ANCESTOR:
1259 fprintf(output, " 'ancestors' "); break;
1260 case AXIS_ANCESTOR_OR_SELF:
1261 fprintf(output, " 'ancestors-or-self' "); break;
1262 case AXIS_ATTRIBUTE:
1263 fprintf(output, " 'attributes' "); break;
1264 case AXIS_CHILD:
1265 fprintf(output, " 'child' "); break;
1266 case AXIS_DESCENDANT:
1267 fprintf(output, " 'descendant' "); break;
1268 case AXIS_DESCENDANT_OR_SELF:
1269 fprintf(output, " 'descendant-or-self' "); break;
1270 case AXIS_FOLLOWING:
1271 fprintf(output, " 'following' "); break;
1272 case AXIS_FOLLOWING_SIBLING:
1273 fprintf(output, " 'following-siblings' "); break;
1274 case AXIS_NAMESPACE:
1275 fprintf(output, " 'namespace' "); break;
1276 case AXIS_PARENT:
1277 fprintf(output, " 'parent' "); break;
1278 case AXIS_PRECEDING:
1279 fprintf(output, " 'preceding' "); break;
1280 case AXIS_PRECEDING_SIBLING:
1281 fprintf(output, " 'preceding-sibling' "); break;
1282 case AXIS_SELF:
1283 fprintf(output, " 'self' "); break;
1284 }
1285 switch (test) {
1286 case NODE_TEST_NONE:
1287 fprintf(output, "'none' "); break;
1288 case NODE_TEST_TYPE:
1289 fprintf(output, "'type' "); break;
1290 case NODE_TEST_PI:
1291 fprintf(output, "'PI' "); break;
1292 case NODE_TEST_ALL:
1293 fprintf(output, "'all' "); break;
1294 case NODE_TEST_NS:
1295 fprintf(output, "'namespace' "); break;
1296 case NODE_TEST_NAME:
1297 fprintf(output, "'name' "); break;
1298 }
1299 switch (type) {
1300 case NODE_TYPE_NODE:
1301 fprintf(output, "'node' "); break;
1302 case NODE_TYPE_COMMENT:
1303 fprintf(output, "'comment' "); break;
1304 case NODE_TYPE_TEXT:
1305 fprintf(output, "'text' "); break;
1306 case NODE_TYPE_PI:
1307 fprintf(output, "'PI' "); break;
1308 }
1309 if (prefix != NULL)
1310 fprintf(output, "%s:", prefix);
1311 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001312 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001313 break;
1314
1315 }
1316 case XPATH_OP_VALUE: {
1317 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1318
1319 fprintf(output, "ELEM ");
1320 xmlXPathDebugDumpObject(output, object, 0);
1321 goto finish;
1322 }
1323 case XPATH_OP_VARIABLE: {
1324 const xmlChar *prefix = op->value5;
1325 const xmlChar *name = op->value4;
1326
1327 if (prefix != NULL)
1328 fprintf(output, "VARIABLE %s:%s", prefix, name);
1329 else
1330 fprintf(output, "VARIABLE %s", name);
1331 break;
1332 }
1333 case XPATH_OP_FUNCTION: {
1334 int nbargs = op->value;
1335 const xmlChar *prefix = op->value5;
1336 const xmlChar *name = op->value4;
1337
1338 if (prefix != NULL)
1339 fprintf(output, "FUNCTION %s:%s(%d args)",
1340 prefix, name, nbargs);
1341 else
1342 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1343 break;
1344 }
1345 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1346 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001347 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001348#ifdef LIBXML_XPTR_ENABLED
1349 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1350#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001351 default:
1352 fprintf(output, "UNKNOWN %d\n", op->op); return;
1353 }
1354 fprintf(output, "\n");
1355finish:
1356 if (op->ch1 >= 0)
1357 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1358 if (op->ch2 >= 0)
1359 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1360}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001361
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001362/**
1363 * xmlXPathDebugDumpCompExpr:
1364 * @output: the FILE * for the output
1365 * @comp: the precompiled XPath expression
1366 * @depth: the indentation level.
1367 *
1368 * Dumps the tree of the compiled XPath expression.
1369 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001370void
1371xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1372 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001373 int i;
1374 char shift[100];
1375
Daniel Veillarda82b1822004-11-08 16:24:57 +00001376 if ((output == NULL) || (comp == NULL)) return;
1377
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001378 for (i = 0;((i < depth) && (i < 25));i++)
1379 shift[2 * i] = shift[2 * i + 1] = ' ';
1380 shift[2 * i] = shift[2 * i + 1] = 0;
1381
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001382 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001383
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001384 fprintf(output, "Compiled Expression : %d elements\n",
1385 comp->nbStep);
1386 i = comp->last;
1387 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1388}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001389
1390#ifdef XP_DEBUG_OBJ_USAGE
1391
1392/*
1393* XPath object usage related debugging variables.
1394*/
1395static int xmlXPathDebugObjCounterUndefined = 0;
1396static int xmlXPathDebugObjCounterNodeset = 0;
1397static int xmlXPathDebugObjCounterBool = 0;
1398static int xmlXPathDebugObjCounterNumber = 0;
1399static int xmlXPathDebugObjCounterString = 0;
1400static int xmlXPathDebugObjCounterPoint = 0;
1401static int xmlXPathDebugObjCounterRange = 0;
1402static int xmlXPathDebugObjCounterLocset = 0;
1403static int xmlXPathDebugObjCounterUsers = 0;
1404static int xmlXPathDebugObjCounterXSLTTree = 0;
1405static int xmlXPathDebugObjCounterAll = 0;
1406
1407static int xmlXPathDebugObjTotalUndefined = 0;
1408static int xmlXPathDebugObjTotalNodeset = 0;
1409static int xmlXPathDebugObjTotalBool = 0;
1410static int xmlXPathDebugObjTotalNumber = 0;
1411static int xmlXPathDebugObjTotalString = 0;
1412static int xmlXPathDebugObjTotalPoint = 0;
1413static int xmlXPathDebugObjTotalRange = 0;
1414static int xmlXPathDebugObjTotalLocset = 0;
1415static int xmlXPathDebugObjTotalUsers = 0;
1416static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001417static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001418
1419static int xmlXPathDebugObjMaxUndefined = 0;
1420static int xmlXPathDebugObjMaxNodeset = 0;
1421static int xmlXPathDebugObjMaxBool = 0;
1422static int xmlXPathDebugObjMaxNumber = 0;
1423static int xmlXPathDebugObjMaxString = 0;
1424static int xmlXPathDebugObjMaxPoint = 0;
1425static int xmlXPathDebugObjMaxRange = 0;
1426static int xmlXPathDebugObjMaxLocset = 0;
1427static int xmlXPathDebugObjMaxUsers = 0;
1428static int xmlXPathDebugObjMaxXSLTTree = 0;
1429static int xmlXPathDebugObjMaxAll = 0;
1430
1431/* REVISIT TODO: Make this static when committing */
1432static void
1433xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1434{
1435 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001436 if (ctxt->cache != NULL) {
1437 xmlXPathContextCachePtr cache =
1438 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001439
1440 cache->dbgCachedAll = 0;
1441 cache->dbgCachedNodeset = 0;
1442 cache->dbgCachedString = 0;
1443 cache->dbgCachedBool = 0;
1444 cache->dbgCachedNumber = 0;
1445 cache->dbgCachedPoint = 0;
1446 cache->dbgCachedRange = 0;
1447 cache->dbgCachedLocset = 0;
1448 cache->dbgCachedUsers = 0;
1449 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001450 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001451
1452 cache->dbgReusedAll = 0;
1453 cache->dbgReusedNodeset = 0;
1454 cache->dbgReusedString = 0;
1455 cache->dbgReusedBool = 0;
1456 cache->dbgReusedNumber = 0;
1457 cache->dbgReusedPoint = 0;
1458 cache->dbgReusedRange = 0;
1459 cache->dbgReusedLocset = 0;
1460 cache->dbgReusedUsers = 0;
1461 cache->dbgReusedXSLTTree = 0;
1462 cache->dbgReusedUndefined = 0;
1463 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001464 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001465
1466 xmlXPathDebugObjCounterUndefined = 0;
1467 xmlXPathDebugObjCounterNodeset = 0;
1468 xmlXPathDebugObjCounterBool = 0;
1469 xmlXPathDebugObjCounterNumber = 0;
1470 xmlXPathDebugObjCounterString = 0;
1471 xmlXPathDebugObjCounterPoint = 0;
1472 xmlXPathDebugObjCounterRange = 0;
1473 xmlXPathDebugObjCounterLocset = 0;
1474 xmlXPathDebugObjCounterUsers = 0;
1475 xmlXPathDebugObjCounterXSLTTree = 0;
1476 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001477
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001478 xmlXPathDebugObjTotalUndefined = 0;
1479 xmlXPathDebugObjTotalNodeset = 0;
1480 xmlXPathDebugObjTotalBool = 0;
1481 xmlXPathDebugObjTotalNumber = 0;
1482 xmlXPathDebugObjTotalString = 0;
1483 xmlXPathDebugObjTotalPoint = 0;
1484 xmlXPathDebugObjTotalRange = 0;
1485 xmlXPathDebugObjTotalLocset = 0;
1486 xmlXPathDebugObjTotalUsers = 0;
1487 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001488 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001489
1490 xmlXPathDebugObjMaxUndefined = 0;
1491 xmlXPathDebugObjMaxNodeset = 0;
1492 xmlXPathDebugObjMaxBool = 0;
1493 xmlXPathDebugObjMaxNumber = 0;
1494 xmlXPathDebugObjMaxString = 0;
1495 xmlXPathDebugObjMaxPoint = 0;
1496 xmlXPathDebugObjMaxRange = 0;
1497 xmlXPathDebugObjMaxLocset = 0;
1498 xmlXPathDebugObjMaxUsers = 0;
1499 xmlXPathDebugObjMaxXSLTTree = 0;
1500 xmlXPathDebugObjMaxAll = 0;
1501
1502}
1503
1504static void
1505xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1506 xmlXPathObjectType objType)
1507{
1508 int isCached = 0;
1509
1510 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001511 if (ctxt->cache != NULL) {
1512 xmlXPathContextCachePtr cache =
1513 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001514
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001515 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001516
1517 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001518 switch (objType) {
1519 case XPATH_UNDEFINED:
1520 cache->dbgReusedUndefined++;
1521 break;
1522 case XPATH_NODESET:
1523 cache->dbgReusedNodeset++;
1524 break;
1525 case XPATH_BOOLEAN:
1526 cache->dbgReusedBool++;
1527 break;
1528 case XPATH_NUMBER:
1529 cache->dbgReusedNumber++;
1530 break;
1531 case XPATH_STRING:
1532 cache->dbgReusedString++;
1533 break;
1534 case XPATH_POINT:
1535 cache->dbgReusedPoint++;
1536 break;
1537 case XPATH_RANGE:
1538 cache->dbgReusedRange++;
1539 break;
1540 case XPATH_LOCATIONSET:
1541 cache->dbgReusedLocset++;
1542 break;
1543 case XPATH_USERS:
1544 cache->dbgReusedUsers++;
1545 break;
1546 case XPATH_XSLT_TREE:
1547 cache->dbgReusedXSLTTree++;
1548 break;
1549 default:
1550 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001551 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001552 }
1553 }
1554
1555 switch (objType) {
1556 case XPATH_UNDEFINED:
1557 if (! isCached)
1558 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001559 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001560 if (xmlXPathDebugObjCounterUndefined >
1561 xmlXPathDebugObjMaxUndefined)
1562 xmlXPathDebugObjMaxUndefined =
1563 xmlXPathDebugObjCounterUndefined;
1564 break;
1565 case XPATH_NODESET:
1566 if (! isCached)
1567 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001568 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001569 if (xmlXPathDebugObjCounterNodeset >
1570 xmlXPathDebugObjMaxNodeset)
1571 xmlXPathDebugObjMaxNodeset =
1572 xmlXPathDebugObjCounterNodeset;
1573 break;
1574 case XPATH_BOOLEAN:
1575 if (! isCached)
1576 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001577 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001578 if (xmlXPathDebugObjCounterBool >
1579 xmlXPathDebugObjMaxBool)
1580 xmlXPathDebugObjMaxBool =
1581 xmlXPathDebugObjCounterBool;
1582 break;
1583 case XPATH_NUMBER:
1584 if (! isCached)
1585 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001586 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001587 if (xmlXPathDebugObjCounterNumber >
1588 xmlXPathDebugObjMaxNumber)
1589 xmlXPathDebugObjMaxNumber =
1590 xmlXPathDebugObjCounterNumber;
1591 break;
1592 case XPATH_STRING:
1593 if (! isCached)
1594 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001595 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001596 if (xmlXPathDebugObjCounterString >
1597 xmlXPathDebugObjMaxString)
1598 xmlXPathDebugObjMaxString =
1599 xmlXPathDebugObjCounterString;
1600 break;
1601 case XPATH_POINT:
1602 if (! isCached)
1603 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001604 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001605 if (xmlXPathDebugObjCounterPoint >
1606 xmlXPathDebugObjMaxPoint)
1607 xmlXPathDebugObjMaxPoint =
1608 xmlXPathDebugObjCounterPoint;
1609 break;
1610 case XPATH_RANGE:
1611 if (! isCached)
1612 xmlXPathDebugObjTotalRange++;
1613 xmlXPathDebugObjCounterRange++;
1614 if (xmlXPathDebugObjCounterRange >
1615 xmlXPathDebugObjMaxRange)
1616 xmlXPathDebugObjMaxRange =
1617 xmlXPathDebugObjCounterRange;
1618 break;
1619 case XPATH_LOCATIONSET:
1620 if (! isCached)
1621 xmlXPathDebugObjTotalLocset++;
1622 xmlXPathDebugObjCounterLocset++;
1623 if (xmlXPathDebugObjCounterLocset >
1624 xmlXPathDebugObjMaxLocset)
1625 xmlXPathDebugObjMaxLocset =
1626 xmlXPathDebugObjCounterLocset;
1627 break;
1628 case XPATH_USERS:
1629 if (! isCached)
1630 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001631 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001632 if (xmlXPathDebugObjCounterUsers >
1633 xmlXPathDebugObjMaxUsers)
1634 xmlXPathDebugObjMaxUsers =
1635 xmlXPathDebugObjCounterUsers;
1636 break;
1637 case XPATH_XSLT_TREE:
1638 if (! isCached)
1639 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001640 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001641 if (xmlXPathDebugObjCounterXSLTTree >
1642 xmlXPathDebugObjMaxXSLTTree)
1643 xmlXPathDebugObjMaxXSLTTree =
1644 xmlXPathDebugObjCounterXSLTTree;
1645 break;
1646 default:
1647 break;
1648 }
1649 if (! isCached)
1650 xmlXPathDebugObjTotalAll++;
1651 xmlXPathDebugObjCounterAll++;
1652 if (xmlXPathDebugObjCounterAll >
1653 xmlXPathDebugObjMaxAll)
1654 xmlXPathDebugObjMaxAll =
1655 xmlXPathDebugObjCounterAll;
1656}
1657
1658static void
1659xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1660 xmlXPathObjectType objType)
1661{
1662 int isCached = 0;
1663
1664 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001665 if (ctxt->cache != NULL) {
1666 xmlXPathContextCachePtr cache =
1667 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001668
Daniel Veillard45490ae2008-07-29 09:13:19 +00001669 isCached = 1;
1670
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001671 cache->dbgCachedAll++;
1672 switch (objType) {
1673 case XPATH_UNDEFINED:
1674 cache->dbgCachedUndefined++;
1675 break;
1676 case XPATH_NODESET:
1677 cache->dbgCachedNodeset++;
1678 break;
1679 case XPATH_BOOLEAN:
1680 cache->dbgCachedBool++;
1681 break;
1682 case XPATH_NUMBER:
1683 cache->dbgCachedNumber++;
1684 break;
1685 case XPATH_STRING:
1686 cache->dbgCachedString++;
1687 break;
1688 case XPATH_POINT:
1689 cache->dbgCachedPoint++;
1690 break;
1691 case XPATH_RANGE:
1692 cache->dbgCachedRange++;
1693 break;
1694 case XPATH_LOCATIONSET:
1695 cache->dbgCachedLocset++;
1696 break;
1697 case XPATH_USERS:
1698 cache->dbgCachedUsers++;
1699 break;
1700 case XPATH_XSLT_TREE:
1701 cache->dbgCachedXSLTTree++;
1702 break;
1703 default:
1704 break;
1705 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001706
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001707 }
1708 }
1709 switch (objType) {
1710 case XPATH_UNDEFINED:
1711 xmlXPathDebugObjCounterUndefined--;
1712 break;
1713 case XPATH_NODESET:
1714 xmlXPathDebugObjCounterNodeset--;
1715 break;
1716 case XPATH_BOOLEAN:
1717 xmlXPathDebugObjCounterBool--;
1718 break;
1719 case XPATH_NUMBER:
1720 xmlXPathDebugObjCounterNumber--;
1721 break;
1722 case XPATH_STRING:
1723 xmlXPathDebugObjCounterString--;
1724 break;
1725 case XPATH_POINT:
1726 xmlXPathDebugObjCounterPoint--;
1727 break;
1728 case XPATH_RANGE:
1729 xmlXPathDebugObjCounterRange--;
1730 break;
1731 case XPATH_LOCATIONSET:
1732 xmlXPathDebugObjCounterLocset--;
1733 break;
1734 case XPATH_USERS:
1735 xmlXPathDebugObjCounterUsers--;
1736 break;
1737 case XPATH_XSLT_TREE:
1738 xmlXPathDebugObjCounterXSLTTree--;
1739 break;
1740 default:
1741 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001742 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001743 xmlXPathDebugObjCounterAll--;
1744}
1745
1746/* REVISIT TODO: Make this static when committing */
1747static void
1748xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1749{
1750 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1751 reqXSLTTree, reqUndefined;
1752 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1753 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1754 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1755 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1756 int leftObjs = xmlXPathDebugObjCounterAll;
1757
1758 reqAll = xmlXPathDebugObjTotalAll;
1759 reqNodeset = xmlXPathDebugObjTotalNodeset;
1760 reqString = xmlXPathDebugObjTotalString;
1761 reqBool = xmlXPathDebugObjTotalBool;
1762 reqNumber = xmlXPathDebugObjTotalNumber;
1763 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1764 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001765
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001766 printf("# XPath object usage:\n");
1767
1768 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001769 if (ctxt->cache != NULL) {
1770 xmlXPathContextCachePtr cache =
1771 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001772
1773 reAll = cache->dbgReusedAll;
1774 reqAll += reAll;
1775 reNodeset = cache->dbgReusedNodeset;
1776 reqNodeset += reNodeset;
1777 reString = cache->dbgReusedString;
1778 reqString += reString;
1779 reBool = cache->dbgReusedBool;
1780 reqBool += reBool;
1781 reNumber = cache->dbgReusedNumber;
1782 reqNumber += reNumber;
1783 reXSLTTree = cache->dbgReusedXSLTTree;
1784 reqXSLTTree += reXSLTTree;
1785 reUndefined = cache->dbgReusedUndefined;
1786 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001787
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001788 caAll = cache->dbgCachedAll;
1789 caBool = cache->dbgCachedBool;
1790 caNodeset = cache->dbgCachedNodeset;
1791 caString = cache->dbgCachedString;
1792 caNumber = cache->dbgCachedNumber;
1793 caXSLTTree = cache->dbgCachedXSLTTree;
1794 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001795
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001796 if (cache->nodesetObjs)
1797 leftObjs -= cache->nodesetObjs->number;
1798 if (cache->stringObjs)
1799 leftObjs -= cache->stringObjs->number;
1800 if (cache->booleanObjs)
1801 leftObjs -= cache->booleanObjs->number;
1802 if (cache->numberObjs)
1803 leftObjs -= cache->numberObjs->number;
1804 if (cache->miscObjs)
1805 leftObjs -= cache->miscObjs->number;
1806 }
1807 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001808
1809 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001810 printf("# total : %d\n", reqAll);
1811 printf("# left : %d\n", leftObjs);
1812 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1813 printf("# reused : %d\n", reAll);
1814 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1815
1816 printf("# node-sets\n");
1817 printf("# total : %d\n", reqNodeset);
1818 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1819 printf("# reused : %d\n", reNodeset);
1820 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1821
1822 printf("# strings\n");
1823 printf("# total : %d\n", reqString);
1824 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1825 printf("# reused : %d\n", reString);
1826 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1827
1828 printf("# booleans\n");
1829 printf("# total : %d\n", reqBool);
1830 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1831 printf("# reused : %d\n", reBool);
1832 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1833
1834 printf("# numbers\n");
1835 printf("# total : %d\n", reqNumber);
1836 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1837 printf("# reused : %d\n", reNumber);
1838 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1839
1840 printf("# XSLT result tree fragments\n");
1841 printf("# total : %d\n", reqXSLTTree);
1842 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1843 printf("# reused : %d\n", reXSLTTree);
1844 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1845
1846 printf("# undefined\n");
1847 printf("# total : %d\n", reqUndefined);
1848 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1849 printf("# reused : %d\n", reUndefined);
1850 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1851
1852}
1853
1854#endif /* XP_DEBUG_OBJ_USAGE */
1855
Daniel Veillard017b1082001-06-21 11:20:21 +00001856#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001857
1858/************************************************************************
1859 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001860 * XPath object caching *
1861 * *
1862 ************************************************************************/
1863
1864/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001865 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001866 *
1867 * Create a new object cache
1868 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001869 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001870 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001871static xmlXPathContextCachePtr
1872xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001873{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001874 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001875
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001876 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001877 if (ret == NULL) {
1878 xmlXPathErrMemory(NULL, "creating object cache\n");
1879 return(NULL);
1880 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001881 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001882 ret->maxNodeset = 100;
1883 ret->maxString = 100;
1884 ret->maxBoolean = 100;
1885 ret->maxNumber = 100;
1886 ret->maxMisc = 100;
1887 return(ret);
1888}
1889
1890static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001891xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001892{
1893 int i;
1894 xmlXPathObjectPtr obj;
1895
1896 if (list == NULL)
1897 return;
1898
1899 for (i = 0; i < list->number; i++) {
1900 obj = list->items[i];
1901 /*
1902 * Note that it is already assured that we don't need to
1903 * look out for namespace nodes in the node-set.
1904 */
1905 if (obj->nodesetval != NULL) {
1906 if (obj->nodesetval->nodeTab != NULL)
1907 xmlFree(obj->nodesetval->nodeTab);
1908 xmlFree(obj->nodesetval);
1909 }
1910 xmlFree(obj);
1911#ifdef XP_DEBUG_OBJ_USAGE
1912 xmlXPathDebugObjCounterAll--;
1913#endif
1914 }
1915 xmlPointerListFree(list);
1916}
1917
1918static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001919xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001920{
1921 if (cache == NULL)
1922 return;
1923 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001924 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001925 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001926 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001927 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001928 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001929 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001930 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001931 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001932 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001933 xmlFree(cache);
1934}
1935
1936/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001937 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001938 *
1939 * @ctxt: the XPath context
1940 * @active: enables/disables (creates/frees) the cache
Daniel Veillard45490ae2008-07-29 09:13:19 +00001941 * @value: a value with semantics dependant on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001942 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001943 *
1944 * Creates/frees an object cache on the XPath context.
1945 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001946 * to be reused.
1947 * @options:
1948 * 0: This will set the XPath object caching:
1949 * @value:
1950 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001951 * to be cached per slot
1952 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001953 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001954 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001955 *
1956 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1957 */
1958int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001959xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1960 int active,
1961 int value,
1962 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001963{
1964 if (ctxt == NULL)
1965 return(-1);
1966 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001967 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001968
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001969 if (ctxt->cache == NULL) {
1970 ctxt->cache = xmlXPathNewCache();
1971 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001972 return(-1);
1973 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001974 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001975 if (options == 0) {
1976 if (value < 0)
1977 value = 100;
1978 cache->maxNodeset = value;
1979 cache->maxString = value;
1980 cache->maxNumber = value;
1981 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001982 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001983 }
1984 } else if (ctxt->cache != NULL) {
1985 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1986 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001987 }
1988 return(0);
1989}
1990
1991/**
1992 * xmlXPathCacheWrapNodeSet:
1993 * @ctxt: the XPath context
1994 * @val: the NodePtr value
1995 *
1996 * This is the cached version of xmlXPathWrapNodeSet().
1997 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1998 *
1999 * Returns the created or reused object.
2000 */
2001static xmlXPathObjectPtr
2002xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002003{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002004 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2005 xmlXPathContextCachePtr cache =
2006 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002007
2008 if ((cache->miscObjs != NULL) &&
2009 (cache->miscObjs->number != 0))
2010 {
2011 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002012
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002013 ret = (xmlXPathObjectPtr)
2014 cache->miscObjs->items[--cache->miscObjs->number];
2015 ret->type = XPATH_NODESET;
2016 ret->nodesetval = val;
2017#ifdef XP_DEBUG_OBJ_USAGE
2018 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2019#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00002020 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002021 }
2022 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002023
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002024 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00002025
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002026}
2027
2028/**
2029 * xmlXPathCacheWrapString:
2030 * @ctxt: the XPath context
2031 * @val: the xmlChar * value
2032 *
2033 * This is the cached version of xmlXPathWrapString().
2034 * Wraps the @val string into an XPath object.
2035 *
2036 * Returns the created or reused object.
2037 */
2038static xmlXPathObjectPtr
2039xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002040{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002041 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2042 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002043
2044 if ((cache->stringObjs != NULL) &&
2045 (cache->stringObjs->number != 0))
2046 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002047
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002048 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002049
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002050 ret = (xmlXPathObjectPtr)
2051 cache->stringObjs->items[--cache->stringObjs->number];
2052 ret->type = XPATH_STRING;
2053 ret->stringval = val;
2054#ifdef XP_DEBUG_OBJ_USAGE
2055 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2056#endif
2057 return(ret);
2058 } else if ((cache->miscObjs != NULL) &&
2059 (cache->miscObjs->number != 0))
2060 {
2061 xmlXPathObjectPtr ret;
2062 /*
2063 * Fallback to misc-cache.
2064 */
2065 ret = (xmlXPathObjectPtr)
2066 cache->miscObjs->items[--cache->miscObjs->number];
2067
2068 ret->type = XPATH_STRING;
2069 ret->stringval = val;
2070#ifdef XP_DEBUG_OBJ_USAGE
2071 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2072#endif
2073 return(ret);
2074 }
2075 }
2076 return(xmlXPathWrapString(val));
2077}
2078
2079/**
2080 * xmlXPathCacheNewNodeSet:
2081 * @ctxt: the XPath context
2082 * @val: the NodePtr value
2083 *
2084 * This is the cached version of xmlXPathNewNodeSet().
2085 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2086 * it with the single Node @val
2087 *
2088 * Returns the created or reused object.
2089 */
2090static xmlXPathObjectPtr
2091xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2092{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002093 if ((ctxt != NULL) && (ctxt->cache)) {
2094 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002095
2096 if ((cache->nodesetObjs != NULL) &&
2097 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002098 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002099 xmlXPathObjectPtr ret;
2100 /*
2101 * Use the nodset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002102 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002103 ret = (xmlXPathObjectPtr)
2104 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2105 ret->type = XPATH_NODESET;
2106 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002107 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002108 if ((ret->nodesetval->nodeMax == 0) ||
2109 (val->type == XML_NAMESPACE_DECL))
2110 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002111 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002112 } else {
2113 ret->nodesetval->nodeTab[0] = val;
2114 ret->nodesetval->nodeNr = 1;
2115 }
2116 }
2117#ifdef XP_DEBUG_OBJ_USAGE
2118 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2119#endif
2120 return(ret);
2121 } else if ((cache->miscObjs != NULL) &&
2122 (cache->miscObjs->number != 0))
2123 {
2124 xmlXPathObjectPtr ret;
2125 /*
2126 * Fallback to misc-cache.
2127 */
2128
2129 ret = (xmlXPathObjectPtr)
2130 cache->miscObjs->items[--cache->miscObjs->number];
2131
2132 ret->type = XPATH_NODESET;
2133 ret->boolval = 0;
2134 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08002135 if (ret->nodesetval == NULL) {
2136 ctxt->lastError.domain = XML_FROM_XPATH;
2137 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2138 return(NULL);
2139 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002140#ifdef XP_DEBUG_OBJ_USAGE
2141 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2142#endif
2143 return(ret);
2144 }
2145 }
2146 return(xmlXPathNewNodeSet(val));
2147}
2148
2149/**
2150 * xmlXPathCacheNewCString:
2151 * @ctxt: the XPath context
2152 * @val: the char * value
2153 *
2154 * This is the cached version of xmlXPathNewCString().
2155 * Acquire an xmlXPathObjectPtr of type string and of value @val
2156 *
2157 * Returns the created or reused object.
2158 */
2159static xmlXPathObjectPtr
2160xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002161{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002162 if ((ctxt != NULL) && (ctxt->cache)) {
2163 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002164
2165 if ((cache->stringObjs != NULL) &&
2166 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002167 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002168 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002169
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002170 ret = (xmlXPathObjectPtr)
2171 cache->stringObjs->items[--cache->stringObjs->number];
2172
2173 ret->type = XPATH_STRING;
2174 ret->stringval = xmlStrdup(BAD_CAST val);
2175#ifdef XP_DEBUG_OBJ_USAGE
2176 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2177#endif
2178 return(ret);
2179 } else if ((cache->miscObjs != NULL) &&
2180 (cache->miscObjs->number != 0))
2181 {
2182 xmlXPathObjectPtr ret;
2183
2184 ret = (xmlXPathObjectPtr)
2185 cache->miscObjs->items[--cache->miscObjs->number];
2186
2187 ret->type = XPATH_STRING;
2188 ret->stringval = xmlStrdup(BAD_CAST val);
2189#ifdef XP_DEBUG_OBJ_USAGE
2190 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2191#endif
2192 return(ret);
2193 }
2194 }
2195 return(xmlXPathNewCString(val));
2196}
2197
2198/**
2199 * xmlXPathCacheNewString:
2200 * @ctxt: the XPath context
2201 * @val: the xmlChar * value
2202 *
2203 * This is the cached version of xmlXPathNewString().
2204 * Acquire an xmlXPathObjectPtr of type string and of value @val
2205 *
2206 * Returns the created or reused object.
2207 */
2208static xmlXPathObjectPtr
2209xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002210{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002211 if ((ctxt != NULL) && (ctxt->cache)) {
2212 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002213
2214 if ((cache->stringObjs != NULL) &&
2215 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002216 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002217 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002218
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002219 ret = (xmlXPathObjectPtr)
2220 cache->stringObjs->items[--cache->stringObjs->number];
2221 ret->type = XPATH_STRING;
2222 if (val != NULL)
2223 ret->stringval = xmlStrdup(val);
2224 else
2225 ret->stringval = xmlStrdup((const xmlChar *)"");
2226#ifdef XP_DEBUG_OBJ_USAGE
2227 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2228#endif
2229 return(ret);
2230 } else if ((cache->miscObjs != NULL) &&
2231 (cache->miscObjs->number != 0))
2232 {
2233 xmlXPathObjectPtr ret;
2234
2235 ret = (xmlXPathObjectPtr)
2236 cache->miscObjs->items[--cache->miscObjs->number];
2237
2238 ret->type = XPATH_STRING;
2239 if (val != NULL)
2240 ret->stringval = xmlStrdup(val);
2241 else
2242 ret->stringval = xmlStrdup((const xmlChar *)"");
2243#ifdef XP_DEBUG_OBJ_USAGE
2244 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2245#endif
2246 return(ret);
2247 }
2248 }
2249 return(xmlXPathNewString(val));
2250}
2251
2252/**
2253 * xmlXPathCacheNewBoolean:
2254 * @ctxt: the XPath context
2255 * @val: the boolean value
2256 *
2257 * This is the cached version of xmlXPathNewBoolean().
2258 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2259 *
2260 * Returns the created or reused object.
2261 */
2262static xmlXPathObjectPtr
2263xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002264{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002265 if ((ctxt != NULL) && (ctxt->cache)) {
2266 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002267
2268 if ((cache->booleanObjs != NULL) &&
2269 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002270 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002271 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002272
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002273 ret = (xmlXPathObjectPtr)
2274 cache->booleanObjs->items[--cache->booleanObjs->number];
2275 ret->type = XPATH_BOOLEAN;
2276 ret->boolval = (val != 0);
2277#ifdef XP_DEBUG_OBJ_USAGE
2278 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2279#endif
2280 return(ret);
2281 } else if ((cache->miscObjs != NULL) &&
2282 (cache->miscObjs->number != 0))
2283 {
2284 xmlXPathObjectPtr ret;
2285
2286 ret = (xmlXPathObjectPtr)
2287 cache->miscObjs->items[--cache->miscObjs->number];
2288
2289 ret->type = XPATH_BOOLEAN;
2290 ret->boolval = (val != 0);
2291#ifdef XP_DEBUG_OBJ_USAGE
2292 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2293#endif
2294 return(ret);
2295 }
2296 }
2297 return(xmlXPathNewBoolean(val));
2298}
2299
2300/**
2301 * xmlXPathCacheNewFloat:
2302 * @ctxt: the XPath context
2303 * @val: the double value
2304 *
2305 * This is the cached version of xmlXPathNewFloat().
2306 * Acquires an xmlXPathObjectPtr of type double and of value @val
2307 *
2308 * Returns the created or reused object.
2309 */
2310static xmlXPathObjectPtr
2311xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2312{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002313 if ((ctxt != NULL) && (ctxt->cache)) {
2314 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002315
2316 if ((cache->numberObjs != NULL) &&
2317 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002318 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002319 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002320
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002321 ret = (xmlXPathObjectPtr)
2322 cache->numberObjs->items[--cache->numberObjs->number];
2323 ret->type = XPATH_NUMBER;
2324 ret->floatval = val;
2325#ifdef XP_DEBUG_OBJ_USAGE
2326 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2327#endif
2328 return(ret);
2329 } else if ((cache->miscObjs != NULL) &&
2330 (cache->miscObjs->number != 0))
2331 {
2332 xmlXPathObjectPtr ret;
2333
2334 ret = (xmlXPathObjectPtr)
2335 cache->miscObjs->items[--cache->miscObjs->number];
2336
2337 ret->type = XPATH_NUMBER;
2338 ret->floatval = val;
2339#ifdef XP_DEBUG_OBJ_USAGE
2340 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2341#endif
2342 return(ret);
2343 }
2344 }
2345 return(xmlXPathNewFloat(val));
2346}
2347
2348/**
2349 * xmlXPathCacheConvertString:
2350 * @ctxt: the XPath context
2351 * @val: an XPath object
2352 *
2353 * This is the cached version of xmlXPathConvertString().
2354 * Converts an existing object to its string() equivalent
2355 *
2356 * Returns a created or reused object, the old one is freed (cached)
2357 * (or the operation is done directly on @val)
2358 */
2359
2360static xmlXPathObjectPtr
2361xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002362 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002363
2364 if (val == NULL)
2365 return(xmlXPathCacheNewCString(ctxt, ""));
2366
2367 switch (val->type) {
2368 case XPATH_UNDEFINED:
2369#ifdef DEBUG_EXPR
2370 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2371#endif
2372 break;
2373 case XPATH_NODESET:
2374 case XPATH_XSLT_TREE:
2375 res = xmlXPathCastNodeSetToString(val->nodesetval);
2376 break;
2377 case XPATH_STRING:
2378 return(val);
2379 case XPATH_BOOLEAN:
2380 res = xmlXPathCastBooleanToString(val->boolval);
2381 break;
2382 case XPATH_NUMBER:
2383 res = xmlXPathCastNumberToString(val->floatval);
2384 break;
2385 case XPATH_USERS:
2386 case XPATH_POINT:
2387 case XPATH_RANGE:
2388 case XPATH_LOCATIONSET:
2389 TODO;
2390 break;
2391 }
2392 xmlXPathReleaseObject(ctxt, val);
2393 if (res == NULL)
2394 return(xmlXPathCacheNewCString(ctxt, ""));
2395 return(xmlXPathCacheWrapString(ctxt, res));
2396}
2397
2398/**
2399 * xmlXPathCacheObjectCopy:
2400 * @ctxt: the XPath context
2401 * @val: the original object
2402 *
2403 * This is the cached version of xmlXPathObjectCopy().
2404 * Acquire a copy of a given object
2405 *
2406 * Returns a created or reused created object.
2407 */
2408static xmlXPathObjectPtr
2409xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2410{
2411 if (val == NULL)
2412 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002413
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002414 if (XP_HAS_CACHE(ctxt)) {
2415 switch (val->type) {
2416 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002417 return(xmlXPathCacheWrapNodeSet(ctxt,
2418 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002419 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002420 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002421 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002422 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002423 case XPATH_NUMBER:
2424 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2425 default:
2426 break;
2427 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002428 }
2429 return(xmlXPathObjectCopy(val));
2430}
2431
2432/**
2433 * xmlXPathCacheConvertBoolean:
2434 * @ctxt: the XPath context
2435 * @val: an XPath object
2436 *
2437 * This is the cached version of xmlXPathConvertBoolean().
2438 * Converts an existing object to its boolean() equivalent
2439 *
2440 * Returns a created or reused object, the old one is freed (or the operation
2441 * is done directly on @val)
2442 */
2443static xmlXPathObjectPtr
2444xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2445 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002446
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002447 if (val == NULL)
2448 return(xmlXPathCacheNewBoolean(ctxt, 0));
2449 if (val->type == XPATH_BOOLEAN)
2450 return(val);
2451 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2452 xmlXPathReleaseObject(ctxt, val);
2453 return(ret);
2454}
2455
2456/**
2457 * xmlXPathCacheConvertNumber:
2458 * @ctxt: the XPath context
2459 * @val: an XPath object
2460 *
2461 * This is the cached version of xmlXPathConvertNumber().
2462 * Converts an existing object to its number() equivalent
2463 *
2464 * Returns a created or reused object, the old one is freed (or the operation
2465 * is done directly on @val)
2466 */
2467static xmlXPathObjectPtr
2468xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2469 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002470
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002471 if (val == NULL)
2472 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2473 if (val->type == XPATH_NUMBER)
2474 return(val);
2475 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2476 xmlXPathReleaseObject(ctxt, val);
2477 return(ret);
2478}
2479
2480/************************************************************************
2481 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002482 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002483 * *
2484 ************************************************************************/
2485
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002486/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002487 * xmlXPathSetFrame:
2488 * @ctxt: an XPath parser context
2489 *
2490 * Set the callee evaluation frame
2491 *
2492 * Returns the previous frame value to be restored once done
2493 */
2494static int
2495xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2496 int ret;
2497
2498 if (ctxt == NULL)
2499 return(0);
2500 ret = ctxt->valueFrame;
2501 ctxt->valueFrame = ctxt->valueNr;
2502 return(ret);
2503}
2504
2505/**
2506 * xmlXPathPopFrame:
2507 * @ctxt: an XPath parser context
2508 * @frame: the previous frame value
2509 *
2510 * Remove the callee evaluation frame
2511 */
2512static void
2513xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2514 if (ctxt == NULL)
2515 return;
2516 if (ctxt->valueNr < ctxt->valueFrame) {
2517 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2518 }
2519 ctxt->valueFrame = frame;
2520}
2521
2522/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002523 * valuePop:
2524 * @ctxt: an XPath evaluation context
2525 *
2526 * Pops the top XPath object from the value stack
2527 *
2528 * Returns the XPath object just removed
2529 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002530xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002531valuePop(xmlXPathParserContextPtr ctxt)
2532{
2533 xmlXPathObjectPtr ret;
2534
Daniel Veillarda82b1822004-11-08 16:24:57 +00002535 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002536 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002537
2538 if (ctxt->valueNr <= ctxt->valueFrame) {
2539 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2540 return (NULL);
2541 }
2542
Daniel Veillard1c732d22002-11-30 11:22:59 +00002543 ctxt->valueNr--;
2544 if (ctxt->valueNr > 0)
2545 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2546 else
2547 ctxt->value = NULL;
2548 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002549 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002550 return (ret);
2551}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002552/**
2553 * valuePush:
2554 * @ctxt: an XPath evaluation context
2555 * @value: the XPath object
2556 *
2557 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002558 *
2559 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002560 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002561int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002562valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2563{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002564 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002565 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002566 xmlXPathObjectPtr *tmp;
2567
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002568 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2569 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2570 ctxt->error = XPATH_MEMORY_ERROR;
2571 return (0);
2572 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002573 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2574 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002575 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002576 if (tmp == NULL) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002577 xmlXPathErrMemory(NULL, "pushing value\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08002578 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002579 return (0);
2580 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002581 ctxt->valueMax *= 2;
2582 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002583 }
2584 ctxt->valueTab[ctxt->valueNr] = value;
2585 ctxt->value = value;
2586 return (ctxt->valueNr++);
2587}
Owen Taylor3473f882001-02-23 17:55:21 +00002588
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002589/**
2590 * xmlXPathPopBoolean:
2591 * @ctxt: an XPath parser context
2592 *
2593 * Pops a boolean from the stack, handling conversion if needed.
2594 * Check error with #xmlXPathCheckError.
2595 *
2596 * Returns the boolean
2597 */
2598int
2599xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2600 xmlXPathObjectPtr obj;
2601 int ret;
2602
2603 obj = valuePop(ctxt);
2604 if (obj == NULL) {
2605 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2606 return(0);
2607 }
William M. Brack08171912003-12-29 02:52:11 +00002608 if (obj->type != XPATH_BOOLEAN)
2609 ret = xmlXPathCastToBoolean(obj);
2610 else
2611 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002612 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002613 return(ret);
2614}
2615
2616/**
2617 * xmlXPathPopNumber:
2618 * @ctxt: an XPath parser context
2619 *
2620 * Pops a number from the stack, handling conversion if needed.
2621 * Check error with #xmlXPathCheckError.
2622 *
2623 * Returns the number
2624 */
2625double
2626xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2627 xmlXPathObjectPtr obj;
2628 double ret;
2629
2630 obj = valuePop(ctxt);
2631 if (obj == NULL) {
2632 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2633 return(0);
2634 }
William M. Brack08171912003-12-29 02:52:11 +00002635 if (obj->type != XPATH_NUMBER)
2636 ret = xmlXPathCastToNumber(obj);
2637 else
2638 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002639 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002640 return(ret);
2641}
2642
2643/**
2644 * xmlXPathPopString:
2645 * @ctxt: an XPath parser context
2646 *
2647 * Pops a string from the stack, handling conversion if needed.
2648 * Check error with #xmlXPathCheckError.
2649 *
2650 * Returns the string
2651 */
2652xmlChar *
2653xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2654 xmlXPathObjectPtr obj;
2655 xmlChar * ret;
2656
2657 obj = valuePop(ctxt);
2658 if (obj == NULL) {
2659 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2660 return(NULL);
2661 }
William M. Brack08171912003-12-29 02:52:11 +00002662 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002663 /* TODO: needs refactoring somewhere else */
2664 if (obj->stringval == ret)
2665 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002666 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002667 return(ret);
2668}
2669
2670/**
2671 * xmlXPathPopNodeSet:
2672 * @ctxt: an XPath parser context
2673 *
2674 * Pops a node-set from the stack, handling conversion if needed.
2675 * Check error with #xmlXPathCheckError.
2676 *
2677 * Returns the node-set
2678 */
2679xmlNodeSetPtr
2680xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2681 xmlXPathObjectPtr obj;
2682 xmlNodeSetPtr ret;
2683
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002684 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002685 if (ctxt->value == NULL) {
2686 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2687 return(NULL);
2688 }
2689 if (!xmlXPathStackIsNodeSet(ctxt)) {
2690 xmlXPathSetTypeError(ctxt);
2691 return(NULL);
2692 }
2693 obj = valuePop(ctxt);
2694 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002695#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002696 /* to fix memory leak of not clearing obj->user */
2697 if (obj->boolval && obj->user != NULL)
2698 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002699#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002700 obj->nodesetval = NULL;
2701 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002702 return(ret);
2703}
2704
2705/**
2706 * xmlXPathPopExternal:
2707 * @ctxt: an XPath parser context
2708 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002709 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002710 * Check error with #xmlXPathCheckError.
2711 *
2712 * Returns the object
2713 */
2714void *
2715xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2716 xmlXPathObjectPtr obj;
2717 void * ret;
2718
Daniel Veillarda82b1822004-11-08 16:24:57 +00002719 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002720 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2721 return(NULL);
2722 }
2723 if (ctxt->value->type != XPATH_USERS) {
2724 xmlXPathSetTypeError(ctxt);
2725 return(NULL);
2726 }
2727 obj = valuePop(ctxt);
2728 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002729 obj->user = NULL;
2730 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002731 return(ret);
2732}
2733
Owen Taylor3473f882001-02-23 17:55:21 +00002734/*
2735 * Macros for accessing the content. Those should be used only by the parser,
2736 * and not exported.
2737 *
2738 * Dirty macros, i.e. one need to make assumption on the context to use them
2739 *
2740 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2741 * CUR returns the current xmlChar value, i.e. a 8 bit value
2742 * in ISO-Latin or UTF-8.
2743 * This should be used internally by the parser
2744 * only to compare to ASCII values otherwise it would break when
2745 * running with UTF-8 encoding.
2746 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2747 * to compare on ASCII based substring.
2748 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2749 * strings within the parser.
2750 * CURRENT Returns the current char value, with the full decoding of
2751 * UTF-8 if we are using this mode. It returns an int.
2752 * NEXT Skip to the next character, this does the proper decoding
2753 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2754 * It returns the pointer to the current xmlChar.
2755 */
2756
2757#define CUR (*ctxt->cur)
2758#define SKIP(val) ctxt->cur += (val)
2759#define NXT(val) ctxt->cur[(val)]
2760#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002761#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2762
2763#define COPY_BUF(l,b,i,v) \
2764 if (l == 1) b[i++] = (xmlChar) v; \
2765 else i += xmlCopyChar(l,&b[i],v)
2766
2767#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002768
Daniel Veillard45490ae2008-07-29 09:13:19 +00002769#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002770 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002771
2772#define CURRENT (*ctxt->cur)
2773#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2774
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002775
2776#ifndef DBL_DIG
2777#define DBL_DIG 16
2778#endif
2779#ifndef DBL_EPSILON
2780#define DBL_EPSILON 1E-9
2781#endif
2782
2783#define UPPER_DOUBLE 1E9
2784#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00002785#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002786
2787#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00002788#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002789#define EXPONENT_DIGITS (3 + 2)
2790
2791/**
2792 * xmlXPathFormatNumber:
2793 * @number: number to format
2794 * @buffer: output buffer
2795 * @buffersize: size of output buffer
2796 *
2797 * Convert the number into a string representation.
2798 */
2799static void
2800xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2801{
Daniel Veillardcda96922001-08-21 10:56:31 +00002802 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002803 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002804 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002805 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002806 break;
2807 case -1:
2808 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002809 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002810 break;
2811 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002812 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002813 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002814 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002815 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002816 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002817 } else if (number == ((int) number)) {
2818 char work[30];
2819 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002820 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002821
2822 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002823 if (value == 0) {
2824 *ptr++ = '0';
2825 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002826 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002827 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002828 while ((*cur) && (ptr - buffer < buffersize)) {
2829 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002830 }
2831 }
2832 if (ptr - buffer < buffersize) {
2833 *ptr = 0;
2834 } else if (buffersize > 0) {
2835 ptr--;
2836 *ptr = 0;
2837 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002838 } else {
William M. Brackca797882007-05-11 14:45:53 +00002839 /*
2840 For the dimension of work,
2841 DBL_DIG is number of significant digits
2842 EXPONENT is only needed for "scientific notation"
2843 3 is sign, decimal point, and terminating zero
2844 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2845 Note that this dimension is slightly (a few characters)
2846 larger than actually necessary.
2847 */
2848 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002849 int integer_place, fraction_place;
2850 char *ptr;
2851 char *after_fraction;
2852 double absolute_value;
2853 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002854
Bjorn Reese70a9da52001-04-21 16:57:29 +00002855 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002856
Bjorn Reese70a9da52001-04-21 16:57:29 +00002857 /*
2858 * First choose format - scientific or regular floating point.
2859 * In either case, result is in work, and after_fraction points
2860 * just past the fractional part.
2861 */
2862 if ( ((absolute_value > UPPER_DOUBLE) ||
2863 (absolute_value < LOWER_DOUBLE)) &&
2864 (absolute_value != 0.0) ) {
2865 /* Use scientific notation */
2866 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2867 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002868 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002869 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002870 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002871
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002872 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002873 else {
2874 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00002875 if (absolute_value > 0.0) {
2876 integer_place = (int)log10(absolute_value);
2877 if (integer_place > 0)
2878 fraction_place = DBL_DIG - integer_place - 1;
2879 else
2880 fraction_place = DBL_DIG - integer_place;
2881 } else {
2882 fraction_place = 1;
2883 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002884 size = snprintf(work, sizeof(work), "%0.*f",
2885 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002886 }
2887
Bjorn Reese70a9da52001-04-21 16:57:29 +00002888 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00002889 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002890 ptr = after_fraction;
2891 while (*(--ptr) == '0')
2892 ;
2893 if (*ptr != '.')
2894 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002895 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002896
2897 /* Finally copy result back to caller */
2898 size = strlen(work) + 1;
2899 if (size > buffersize) {
2900 work[buffersize - 1] = 0;
2901 size = buffersize;
2902 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002903 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002904 }
2905 break;
2906 }
2907}
2908
Owen Taylor3473f882001-02-23 17:55:21 +00002909
2910/************************************************************************
2911 * *
2912 * Routines to handle NodeSets *
2913 * *
2914 ************************************************************************/
2915
2916/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002917 * xmlXPathOrderDocElems:
2918 * @doc: an input document
2919 *
2920 * Call this routine to speed up XPath computation on static documents.
2921 * This stamps all the element nodes with the document order
2922 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002923 * field, the value stored is actually - the node number (starting at -1)
2924 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002925 *
William M. Brack08171912003-12-29 02:52:11 +00002926 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002927 * of error.
2928 */
2929long
2930xmlXPathOrderDocElems(xmlDocPtr doc) {
2931 long count = 0;
2932 xmlNodePtr cur;
2933
2934 if (doc == NULL)
2935 return(-1);
2936 cur = doc->children;
2937 while (cur != NULL) {
2938 if (cur->type == XML_ELEMENT_NODE) {
2939 cur->content = (void *) (-(++count));
2940 if (cur->children != NULL) {
2941 cur = cur->children;
2942 continue;
2943 }
2944 }
2945 if (cur->next != NULL) {
2946 cur = cur->next;
2947 continue;
2948 }
2949 do {
2950 cur = cur->parent;
2951 if (cur == NULL)
2952 break;
2953 if (cur == (xmlNodePtr) doc) {
2954 cur = NULL;
2955 break;
2956 }
2957 if (cur->next != NULL) {
2958 cur = cur->next;
2959 break;
2960 }
2961 } while (cur != NULL);
2962 }
2963 return(count);
2964}
2965
2966/**
Owen Taylor3473f882001-02-23 17:55:21 +00002967 * xmlXPathCmpNodes:
2968 * @node1: the first node
2969 * @node2: the second node
2970 *
2971 * Compare two nodes w.r.t document order
2972 *
2973 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002974 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002975 */
2976int
2977xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2978 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002979 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002980 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002981 xmlNodePtr cur, root;
2982
2983 if ((node1 == NULL) || (node2 == NULL))
2984 return(-2);
2985 /*
2986 * a couple of optimizations which will avoid computations in most cases
2987 */
William M. Brackee0b9822007-03-07 08:15:01 +00002988 if (node1 == node2) /* trivial case */
2989 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00002990 if (node1->type == XML_ATTRIBUTE_NODE) {
2991 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002992 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002993 node1 = node1->parent;
2994 }
2995 if (node2->type == XML_ATTRIBUTE_NODE) {
2996 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002997 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002998 node2 = node2->parent;
2999 }
3000 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00003001 if (attr1 == attr2) {
3002 /* not required, but we keep attributes in order */
3003 if (attr1 != 0) {
3004 cur = attrNode2->prev;
3005 while (cur != NULL) {
3006 if (cur == attrNode1)
3007 return (1);
3008 cur = cur->prev;
3009 }
3010 return (-1);
3011 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003012 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00003013 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003014 if (attr2 == 1)
3015 return(1);
3016 return(-1);
3017 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003018 if ((node1->type == XML_NAMESPACE_DECL) ||
3019 (node2->type == XML_NAMESPACE_DECL))
3020 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003021 if (node1 == node2->prev)
3022 return(1);
3023 if (node1 == node2->next)
3024 return(-1);
3025
3026 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003027 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003028 */
3029 if ((node1->type == XML_ELEMENT_NODE) &&
3030 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003031 (0 > (long) node1->content) &&
3032 (0 > (long) node2->content) &&
3033 (node1->doc == node2->doc)) {
3034 long l1, l2;
3035
3036 l1 = -((long) node1->content);
3037 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003038 if (l1 < l2)
3039 return(1);
3040 if (l1 > l2)
3041 return(-1);
3042 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003043
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003044 /*
Owen Taylor3473f882001-02-23 17:55:21 +00003045 * compute depth to root
3046 */
3047 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3048 if (cur == node1)
3049 return(1);
3050 depth2++;
3051 }
3052 root = cur;
3053 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3054 if (cur == node2)
3055 return(-1);
3056 depth1++;
3057 }
3058 /*
3059 * Distinct document (or distinct entities :-( ) case.
3060 */
3061 if (root != cur) {
3062 return(-2);
3063 }
3064 /*
3065 * get the nearest common ancestor.
3066 */
3067 while (depth1 > depth2) {
3068 depth1--;
3069 node1 = node1->parent;
3070 }
3071 while (depth2 > depth1) {
3072 depth2--;
3073 node2 = node2->parent;
3074 }
3075 while (node1->parent != node2->parent) {
3076 node1 = node1->parent;
3077 node2 = node2->parent;
3078 /* should not happen but just in case ... */
3079 if ((node1 == NULL) || (node2 == NULL))
3080 return(-2);
3081 }
3082 /*
3083 * Find who's first.
3084 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003085 if (node1 == node2->prev)
3086 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003087 if (node1 == node2->next)
3088 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003089 /*
3090 * Speedup using document order if availble.
3091 */
3092 if ((node1->type == XML_ELEMENT_NODE) &&
3093 (node2->type == XML_ELEMENT_NODE) &&
3094 (0 > (long) node1->content) &&
3095 (0 > (long) node2->content) &&
3096 (node1->doc == node2->doc)) {
3097 long l1, l2;
3098
3099 l1 = -((long) node1->content);
3100 l2 = -((long) node2->content);
3101 if (l1 < l2)
3102 return(1);
3103 if (l1 > l2)
3104 return(-1);
3105 }
3106
Owen Taylor3473f882001-02-23 17:55:21 +00003107 for (cur = node1->next;cur != NULL;cur = cur->next)
3108 if (cur == node2)
3109 return(1);
3110 return(-1); /* assume there is no sibling list corruption */
3111}
3112
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003113#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003114/**
3115 * xmlXPathCmpNodesExt:
3116 * @node1: the first node
3117 * @node2: the second node
3118 *
3119 * Compare two nodes w.r.t document order.
3120 * This one is optimized for handling of non-element nodes.
3121 *
3122 * Returns -2 in case of error 1 if first point < second point, 0 if
3123 * it's the same node, -1 otherwise
3124 */
3125static int
3126xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3127 int depth1, depth2;
3128 int misc = 0, precedence1 = 0, precedence2 = 0;
3129 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3130 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003131 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003132
3133 if ((node1 == NULL) || (node2 == NULL))
3134 return(-2);
3135
3136 if (node1 == node2)
3137 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00003138
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003139 /*
3140 * a couple of optimizations which will avoid computations in most cases
Daniel Veillard45490ae2008-07-29 09:13:19 +00003141 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003142 switch (node1->type) {
3143 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003144 if (node2->type == XML_ELEMENT_NODE) {
3145 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3146 (0 > (long) node2->content) &&
3147 (node1->doc == node2->doc))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003148 {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003149 l1 = -((long) node1->content);
3150 l2 = -((long) node2->content);
3151 if (l1 < l2)
3152 return(1);
3153 if (l1 > l2)
3154 return(-1);
3155 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003156 goto turtle_comparison;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003157 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003158 break;
3159 case XML_ATTRIBUTE_NODE:
3160 precedence1 = 1; /* element is owner */
3161 miscNode1 = node1;
3162 node1 = node1->parent;
3163 misc = 1;
3164 break;
3165 case XML_TEXT_NODE:
3166 case XML_CDATA_SECTION_NODE:
3167 case XML_COMMENT_NODE:
3168 case XML_PI_NODE: {
3169 miscNode1 = node1;
3170 /*
3171 * Find nearest element node.
Daniel Veillard45490ae2008-07-29 09:13:19 +00003172 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003173 if (node1->prev != NULL) {
3174 do {
3175 node1 = node1->prev;
3176 if (node1->type == XML_ELEMENT_NODE) {
3177 precedence1 = 3; /* element in prev-sibl axis */
3178 break;
3179 }
3180 if (node1->prev == NULL) {
3181 precedence1 = 2; /* element is parent */
3182 /*
3183 * URGENT TODO: Are there any cases, where the
3184 * parent of such a node is not an element node?
3185 */
3186 node1 = node1->parent;
3187 break;
3188 }
3189 } while (1);
3190 } else {
3191 precedence1 = 2; /* element is parent */
3192 node1 = node1->parent;
3193 }
William M. Brack31700e62007-06-13 20:33:02 +00003194 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3195 (0 <= (long) node1->content)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003196 /*
3197 * Fallback for whatever case.
3198 */
3199 node1 = miscNode1;
3200 precedence1 = 0;
3201 } else
3202 misc = 1;
3203 }
3204 break;
3205 case XML_NAMESPACE_DECL:
3206 /*
3207 * TODO: why do we return 1 for namespace nodes?
3208 */
3209 return(1);
3210 default:
3211 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003212 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003213 switch (node2->type) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003214 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003215 break;
3216 case XML_ATTRIBUTE_NODE:
3217 precedence2 = 1; /* element is owner */
3218 miscNode2 = node2;
3219 node2 = node2->parent;
3220 misc = 1;
3221 break;
3222 case XML_TEXT_NODE:
3223 case XML_CDATA_SECTION_NODE:
3224 case XML_COMMENT_NODE:
3225 case XML_PI_NODE: {
3226 miscNode2 = node2;
3227 if (node2->prev != NULL) {
3228 do {
3229 node2 = node2->prev;
3230 if (node2->type == XML_ELEMENT_NODE) {
3231 precedence2 = 3; /* element in prev-sibl axis */
3232 break;
3233 }
3234 if (node2->prev == NULL) {
3235 precedence2 = 2; /* element is parent */
3236 node2 = node2->parent;
3237 break;
3238 }
3239 } while (1);
3240 } else {
3241 precedence2 = 2; /* element is parent */
3242 node2 = node2->parent;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003243 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003244 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3245 (0 <= (long) node1->content))
3246 {
3247 node2 = miscNode2;
3248 precedence2 = 0;
3249 } else
3250 misc = 1;
3251 }
3252 break;
3253 case XML_NAMESPACE_DECL:
3254 return(1);
3255 default:
3256 break;
3257 }
3258 if (misc) {
3259 if (node1 == node2) {
3260 if (precedence1 == precedence2) {
3261 /*
3262 * The ugly case; but normally there aren't many
3263 * adjacent non-element nodes around.
3264 */
3265 cur = miscNode2->prev;
3266 while (cur != NULL) {
3267 if (cur == miscNode1)
3268 return(1);
3269 if (cur->type == XML_ELEMENT_NODE)
3270 return(-1);
3271 cur = cur->prev;
3272 }
3273 return (-1);
3274 } else {
3275 /*
3276 * Evaluate based on higher precedence wrt to the element.
3277 * TODO: This assumes attributes are sorted before content.
3278 * Is this 100% correct?
3279 */
3280 if (precedence1 < precedence2)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003281 return(1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003282 else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003283 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003284 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003285 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003286 /*
3287 * Special case: One of the helper-elements is contained by the other.
3288 * <foo>
3289 * <node2>
3290 * <node1>Text-1(precedence1 == 2)</node1>
3291 * </node2>
3292 * Text-6(precedence2 == 3)
3293 * </foo>
Daniel Veillard45490ae2008-07-29 09:13:19 +00003294 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003295 if ((precedence2 == 3) && (precedence1 > 1)) {
3296 cur = node1->parent;
3297 while (cur) {
3298 if (cur == node2)
3299 return(1);
3300 cur = cur->parent;
3301 }
3302 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003303 if ((precedence1 == 3) && (precedence2 > 1)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003304 cur = node2->parent;
3305 while (cur) {
3306 if (cur == node1)
3307 return(-1);
3308 cur = cur->parent;
3309 }
3310 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003311 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003312
3313 /*
3314 * Speedup using document order if availble.
3315 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003316 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003317 (node2->type == XML_ELEMENT_NODE) &&
3318 (0 > (long) node1->content) &&
3319 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003320 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003321
3322 l1 = -((long) node1->content);
3323 l2 = -((long) node2->content);
3324 if (l1 < l2)
3325 return(1);
3326 if (l1 > l2)
3327 return(-1);
3328 }
3329
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003330turtle_comparison:
3331
3332 if (node1 == node2->prev)
3333 return(1);
3334 if (node1 == node2->next)
3335 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003336 /*
3337 * compute depth to root
3338 */
3339 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3340 if (cur == node1)
3341 return(1);
3342 depth2++;
3343 }
3344 root = cur;
3345 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3346 if (cur == node2)
3347 return(-1);
3348 depth1++;
3349 }
3350 /*
3351 * Distinct document (or distinct entities :-( ) case.
3352 */
3353 if (root != cur) {
3354 return(-2);
3355 }
3356 /*
3357 * get the nearest common ancestor.
3358 */
3359 while (depth1 > depth2) {
3360 depth1--;
3361 node1 = node1->parent;
3362 }
3363 while (depth2 > depth1) {
3364 depth2--;
3365 node2 = node2->parent;
3366 }
3367 while (node1->parent != node2->parent) {
3368 node1 = node1->parent;
3369 node2 = node2->parent;
3370 /* should not happen but just in case ... */
3371 if ((node1 == NULL) || (node2 == NULL))
3372 return(-2);
3373 }
3374 /*
3375 * Find who's first.
3376 */
3377 if (node1 == node2->prev)
3378 return(1);
3379 if (node1 == node2->next)
3380 return(-1);
3381 /*
3382 * Speedup using document order if availble.
3383 */
3384 if ((node1->type == XML_ELEMENT_NODE) &&
3385 (node2->type == XML_ELEMENT_NODE) &&
3386 (0 > (long) node1->content) &&
3387 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003388 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003389
3390 l1 = -((long) node1->content);
3391 l2 = -((long) node2->content);
3392 if (l1 < l2)
3393 return(1);
3394 if (l1 > l2)
3395 return(-1);
3396 }
3397
3398 for (cur = node1->next;cur != NULL;cur = cur->next)
3399 if (cur == node2)
3400 return(1);
3401 return(-1); /* assume there is no sibling list corruption */
3402}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003403#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003404
Owen Taylor3473f882001-02-23 17:55:21 +00003405/**
3406 * xmlXPathNodeSetSort:
3407 * @set: the node set
3408 *
3409 * Sort the node set in document order
3410 */
3411void
3412xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Vojtech Fried3e031b72012-08-24 16:52:44 +08003413#ifndef WITH_TIM_SORT
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003414 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003415 xmlNodePtr tmp;
Vojtech Fried3e031b72012-08-24 16:52:44 +08003416#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003417
3418 if (set == NULL)
3419 return;
3420
Vojtech Fried3e031b72012-08-24 16:52:44 +08003421#ifndef WITH_TIM_SORT
3422 /*
3423 * Use the old Shell's sort implementation to sort the node-set
3424 * Timsort ought to be quite faster
3425 */
Owen Taylor3473f882001-02-23 17:55:21 +00003426 len = set->nodeNr;
3427 for (incr = len / 2; incr > 0; incr /= 2) {
3428 for (i = incr; i < len; i++) {
3429 j = i - incr;
3430 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003431#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003432 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3433 set->nodeTab[j + incr]) == -1)
3434#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003435 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003436 set->nodeTab[j + incr]) == -1)
3437#endif
3438 {
Owen Taylor3473f882001-02-23 17:55:21 +00003439 tmp = set->nodeTab[j];
3440 set->nodeTab[j] = set->nodeTab[j + incr];
3441 set->nodeTab[j + incr] = tmp;
3442 j -= incr;
3443 } else
3444 break;
3445 }
3446 }
3447 }
Vojtech Fried3e031b72012-08-24 16:52:44 +08003448#else /* WITH_TIM_SORT */
3449 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3450#endif /* WITH_TIM_SORT */
Owen Taylor3473f882001-02-23 17:55:21 +00003451}
3452
3453#define XML_NODESET_DEFAULT 10
3454/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003455 * xmlXPathNodeSetDupNs:
3456 * @node: the parent node of the namespace XPath node
3457 * @ns: the libxml namespace declaration node.
3458 *
3459 * Namespace node in libxml don't match the XPath semantic. In a node set
3460 * the namespace nodes are duplicated and the next pointer is set to the
3461 * parent node in the XPath semantic.
3462 *
3463 * Returns the newly created object.
3464 */
3465static xmlNodePtr
3466xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3467 xmlNsPtr cur;
3468
3469 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3470 return(NULL);
3471 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3472 return((xmlNodePtr) ns);
3473
3474 /*
3475 * Allocate a new Namespace and fill the fields.
3476 */
3477 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3478 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003479 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003480 return(NULL);
3481 }
3482 memset(cur, 0, sizeof(xmlNs));
3483 cur->type = XML_NAMESPACE_DECL;
3484 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003485 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003486 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003487 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003488 cur->next = (xmlNsPtr) node;
3489 return((xmlNodePtr) cur);
3490}
3491
3492/**
3493 * xmlXPathNodeSetFreeNs:
3494 * @ns: the XPath namespace node found in a nodeset.
3495 *
William M. Brack08171912003-12-29 02:52:11 +00003496 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003497 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003498 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003499 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003500void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003501xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3502 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3503 return;
3504
3505 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3506 if (ns->href != NULL)
3507 xmlFree((xmlChar *)ns->href);
3508 if (ns->prefix != NULL)
3509 xmlFree((xmlChar *)ns->prefix);
3510 xmlFree(ns);
3511 }
3512}
3513
3514/**
Owen Taylor3473f882001-02-23 17:55:21 +00003515 * xmlXPathNodeSetCreate:
3516 * @val: an initial xmlNodePtr, or NULL
3517 *
3518 * Create a new xmlNodeSetPtr of type double and of value @val
3519 *
3520 * Returns the newly created object.
3521 */
3522xmlNodeSetPtr
3523xmlXPathNodeSetCreate(xmlNodePtr val) {
3524 xmlNodeSetPtr ret;
3525
3526 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3527 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003528 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003529 return(NULL);
3530 }
3531 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3532 if (val != NULL) {
3533 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3534 sizeof(xmlNodePtr));
3535 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003536 xmlXPathErrMemory(NULL, "creating nodeset\n");
3537 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003538 return(NULL);
3539 }
3540 memset(ret->nodeTab, 0 ,
3541 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3542 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003543 if (val->type == XML_NAMESPACE_DECL) {
3544 xmlNsPtr ns = (xmlNsPtr) val;
3545
3546 ret->nodeTab[ret->nodeNr++] =
3547 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3548 } else
3549 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003550 }
3551 return(ret);
3552}
3553
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003554/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003555 * xmlXPathNodeSetCreateSize:
3556 * @size: the initial size of the set
3557 *
3558 * Create a new xmlNodeSetPtr of type double and of value @val
3559 *
3560 * Returns the newly created object.
3561 */
3562static xmlNodeSetPtr
3563xmlXPathNodeSetCreateSize(int size) {
3564 xmlNodeSetPtr ret;
3565
3566 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3567 if (ret == NULL) {
3568 xmlXPathErrMemory(NULL, "creating nodeset\n");
3569 return(NULL);
3570 }
3571 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3572 if (size < XML_NODESET_DEFAULT)
3573 size = XML_NODESET_DEFAULT;
3574 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3575 if (ret->nodeTab == NULL) {
3576 xmlXPathErrMemory(NULL, "creating nodeset\n");
3577 xmlFree(ret);
3578 return(NULL);
3579 }
3580 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003581 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003582 return(ret);
3583}
3584
3585/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003586 * xmlXPathNodeSetContains:
3587 * @cur: the node-set
3588 * @val: the node
3589 *
3590 * checks whether @cur contains @val
3591 *
3592 * Returns true (1) if @cur contains @val, false (0) otherwise
3593 */
3594int
3595xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3596 int i;
3597
Daniel Veillarda82b1822004-11-08 16:24:57 +00003598 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003599 if (val->type == XML_NAMESPACE_DECL) {
3600 for (i = 0; i < cur->nodeNr; i++) {
3601 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3602 xmlNsPtr ns1, ns2;
3603
3604 ns1 = (xmlNsPtr) val;
3605 ns2 = (xmlNsPtr) cur->nodeTab[i];
3606 if (ns1 == ns2)
3607 return(1);
3608 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3609 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3610 return(1);
3611 }
3612 }
3613 } else {
3614 for (i = 0; i < cur->nodeNr; i++) {
3615 if (cur->nodeTab[i] == val)
3616 return(1);
3617 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003618 }
3619 return(0);
3620}
3621
3622/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003623 * xmlXPathNodeSetAddNs:
3624 * @cur: the initial node set
3625 * @node: the hosting node
3626 * @ns: a the namespace node
3627 *
3628 * add a new namespace node to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003629 *
3630 * Returns 0 in case of success and -1 in case of error
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003631 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003632int
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003633xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3634 int i;
3635
Daniel Veillard45490ae2008-07-29 09:13:19 +00003636
Daniel Veillarda82b1822004-11-08 16:24:57 +00003637 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3638 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003639 (node->type != XML_ELEMENT_NODE))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003640 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003641
William M. Brack08171912003-12-29 02:52:11 +00003642 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003643 /*
William M. Brack08171912003-12-29 02:52:11 +00003644 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003645 */
3646 for (i = 0;i < cur->nodeNr;i++) {
3647 if ((cur->nodeTab[i] != NULL) &&
3648 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003649 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003650 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003651 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003652 }
3653
3654 /*
3655 * grow the nodeTab if needed
3656 */
3657 if (cur->nodeMax == 0) {
3658 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3659 sizeof(xmlNodePtr));
3660 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003661 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003662 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003663 }
3664 memset(cur->nodeTab, 0 ,
3665 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3666 cur->nodeMax = XML_NODESET_DEFAULT;
3667 } else if (cur->nodeNr == cur->nodeMax) {
3668 xmlNodePtr *temp;
3669
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003670 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3671 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003672 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003673 }
Chris Evansd7958b22011-03-23 08:13:06 +08003674 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003675 sizeof(xmlNodePtr));
3676 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003677 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003678 return(-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003679 }
Chris Evansd7958b22011-03-23 08:13:06 +08003680 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003681 cur->nodeTab = temp;
3682 }
3683 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003684 return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003685}
3686
3687/**
Owen Taylor3473f882001-02-23 17:55:21 +00003688 * xmlXPathNodeSetAdd:
3689 * @cur: the initial node set
3690 * @val: a new xmlNodePtr
3691 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003692 * add a new xmlNodePtr to an existing NodeSet
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003693 *
3694 * Returns 0 in case of success, and -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00003695 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003696int
Owen Taylor3473f882001-02-23 17:55:21 +00003697xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3698 int i;
3699
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003700 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003701
William M. Brack08171912003-12-29 02:52:11 +00003702 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003703 /*
William M. Brack08171912003-12-29 02:52:11 +00003704 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003705 */
3706 for (i = 0;i < cur->nodeNr;i++)
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003707 if (cur->nodeTab[i] == val) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003708
3709 /*
3710 * grow the nodeTab if needed
3711 */
3712 if (cur->nodeMax == 0) {
3713 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3714 sizeof(xmlNodePtr));
3715 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003716 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003717 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003718 }
3719 memset(cur->nodeTab, 0 ,
3720 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3721 cur->nodeMax = XML_NODESET_DEFAULT;
3722 } else if (cur->nodeNr == cur->nodeMax) {
3723 xmlNodePtr *temp;
3724
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003725 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3726 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003727 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003728 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003729 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003730 sizeof(xmlNodePtr));
3731 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003732 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003733 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003734 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003735 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003736 cur->nodeTab = temp;
3737 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003738 if (val->type == XML_NAMESPACE_DECL) {
3739 xmlNsPtr ns = (xmlNsPtr) val;
3740
Daniel Veillard45490ae2008-07-29 09:13:19 +00003741 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003742 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3743 } else
3744 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003745 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003746}
3747
3748/**
3749 * xmlXPathNodeSetAddUnique:
3750 * @cur: the initial node set
3751 * @val: a new xmlNodePtr
3752 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003753 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003754 * when we are sure the node is not already in the set.
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003755 *
3756 * Returns 0 in case of success and -1 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00003757 */
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003758int
Owen Taylor3473f882001-02-23 17:55:21 +00003759xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003760 if ((cur == NULL) || (val == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003761
William M. Brack08171912003-12-29 02:52:11 +00003762 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003763 /*
3764 * grow the nodeTab if needed
3765 */
3766 if (cur->nodeMax == 0) {
3767 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3768 sizeof(xmlNodePtr));
3769 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003770 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003771 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003772 }
3773 memset(cur->nodeTab, 0 ,
3774 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3775 cur->nodeMax = XML_NODESET_DEFAULT;
3776 } else if (cur->nodeNr == cur->nodeMax) {
3777 xmlNodePtr *temp;
3778
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003779 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3780 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003781 return(-1);
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003782 }
Chris Evansd7958b22011-03-23 08:13:06 +08003783 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003784 sizeof(xmlNodePtr));
3785 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003786 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003787 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003788 }
3789 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003790 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003791 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003792 if (val->type == XML_NAMESPACE_DECL) {
3793 xmlNsPtr ns = (xmlNsPtr) val;
3794
Daniel Veillard45490ae2008-07-29 09:13:19 +00003795 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003796 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3797 } else
3798 cur->nodeTab[cur->nodeNr++] = val;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08003799 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003800}
3801
3802/**
3803 * xmlXPathNodeSetMerge:
3804 * @val1: the first NodeSet or NULL
3805 * @val2: the second NodeSet
3806 *
3807 * Merges two nodesets, all nodes from @val2 are added to @val1
3808 * if @val1 is NULL, a new set is created and copied from @val2
3809 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003810 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003811 */
3812xmlNodeSetPtr
3813xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003814 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003815 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003816
3817 if (val2 == NULL) return(val1);
3818 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003819 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003820 if (val1 == NULL)
3821 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003822#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003823 /*
3824 * TODO: The optimization won't work in every case, since
3825 * those nasty namespace nodes need to be added with
3826 * xmlXPathNodeSetDupNs() to the set; thus a pure
3827 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003828 * If there was a flag on the nodesetval, indicating that
3829 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003830 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003831 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003832 * Optimization: Create an equally sized node-set
3833 * and memcpy the content.
3834 */
3835 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3836 if (val1 == NULL)
3837 return(NULL);
3838 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003839 if (val2->nodeNr == 1)
3840 *(val1->nodeTab) = *(val2->nodeTab);
3841 else {
3842 memcpy(val1->nodeTab, val2->nodeTab,
3843 val2->nodeNr * sizeof(xmlNodePtr));
3844 }
3845 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003846 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003847 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003848#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003849 }
3850
William M. Brack08171912003-12-29 02:52:11 +00003851 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003852 initNr = val1->nodeNr;
3853
3854 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003855 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003856 /*
William M. Brack08171912003-12-29 02:52:11 +00003857 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003858 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003859 skip = 0;
3860 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003861 n1 = val1->nodeTab[j];
3862 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003863 skip = 1;
3864 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003865 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003866 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003867 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3868 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3869 ((xmlNsPtr) n2)->prefix)))
3870 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003871 skip = 1;
3872 break;
3873 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003874 }
3875 }
3876 if (skip)
3877 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003878
3879 /*
3880 * grow the nodeTab if needed
3881 */
3882 if (val1->nodeMax == 0) {
3883 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3884 sizeof(xmlNodePtr));
3885 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003886 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003887 return(NULL);
3888 }
3889 memset(val1->nodeTab, 0 ,
3890 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3891 val1->nodeMax = XML_NODESET_DEFAULT;
3892 } else if (val1->nodeNr == val1->nodeMax) {
3893 xmlNodePtr *temp;
3894
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003895 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3896 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3897 return(NULL);
3898 }
Chris Evansd7958b22011-03-23 08:13:06 +08003899 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003900 sizeof(xmlNodePtr));
3901 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003902 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003903 return(NULL);
3904 }
3905 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003906 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003907 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003908 if (n2->type == XML_NAMESPACE_DECL) {
3909 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003910
3911 val1->nodeTab[val1->nodeNr++] =
3912 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3913 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003914 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003915 }
3916
3917 return(val1);
3918}
3919
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003920
3921/**
3922 * xmlXPathNodeSetMergeAndClear:
3923 * @set1: the first NodeSet or NULL
3924 * @set2: the second NodeSet
3925 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3926 *
3927 * Merges two nodesets, all nodes from @set2 are added to @set1
3928 * if @set1 is NULL, a new set is created and copied from @set2.
3929 * Checks for duplicate nodes. Clears set2.
3930 *
3931 * Returns @set1 once extended or NULL in case of error.
3932 */
3933static xmlNodeSetPtr
3934xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3935 int hasNullEntries)
3936{
3937 if ((set1 == NULL) && (hasNullEntries == 0)) {
3938 /*
3939 * Note that doing a memcpy of the list, namespace nodes are
3940 * just assigned to set1, since set2 is cleared anyway.
3941 */
3942 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3943 if (set1 == NULL)
3944 return(NULL);
3945 if (set2->nodeNr != 0) {
3946 memcpy(set1->nodeTab, set2->nodeTab,
3947 set2->nodeNr * sizeof(xmlNodePtr));
3948 set1->nodeNr = set2->nodeNr;
3949 }
3950 } else {
3951 int i, j, initNbSet1;
3952 xmlNodePtr n1, n2;
3953
3954 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003955 set1 = xmlXPathNodeSetCreate(NULL);
3956 if (set1 == NULL)
3957 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003958
Daniel Veillard45490ae2008-07-29 09:13:19 +00003959 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003960 for (i = 0;i < set2->nodeNr;i++) {
3961 n2 = set2->nodeTab[i];
3962 /*
3963 * Skip NULLed entries.
3964 */
3965 if (n2 == NULL)
3966 continue;
3967 /*
3968 * Skip duplicates.
3969 */
3970 for (j = 0; j < initNbSet1; j++) {
3971 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003972 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003973 goto skip_node;
3974 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3975 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003976 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003977 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3978 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3979 ((xmlNsPtr) n2)->prefix)))
3980 {
3981 /*
3982 * Free the namespace node.
3983 */
3984 set2->nodeTab[i] = NULL;
3985 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3986 goto skip_node;
3987 }
3988 }
3989 }
3990 /*
3991 * grow the nodeTab if needed
3992 */
3993 if (set1->nodeMax == 0) {
3994 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3995 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3996 if (set1->nodeTab == NULL) {
3997 xmlXPathErrMemory(NULL, "merging nodeset\n");
3998 return(NULL);
3999 }
4000 memset(set1->nodeTab, 0,
4001 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4002 set1->nodeMax = XML_NODESET_DEFAULT;
4003 } else if (set1->nodeNr >= set1->nodeMax) {
4004 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004005
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004006 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4007 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4008 return(NULL);
4009 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004010 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004011 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004012 if (temp == NULL) {
4013 xmlXPathErrMemory(NULL, "merging nodeset\n");
4014 return(NULL);
4015 }
4016 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004017 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004018 }
4019 if (n2->type == XML_NAMESPACE_DECL) {
4020 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004021
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004022 set1->nodeTab[set1->nodeNr++] =
4023 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
4024 } else
4025 set1->nodeTab[set1->nodeNr++] = n2;
4026skip_node:
4027 {}
4028 }
4029 }
4030 set2->nodeNr = 0;
4031 return(set1);
4032}
4033
4034/**
4035 * xmlXPathNodeSetMergeAndClearNoDupls:
4036 * @set1: the first NodeSet or NULL
4037 * @set2: the second NodeSet
4038 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4039 *
4040 * Merges two nodesets, all nodes from @set2 are added to @set1
4041 * if @set1 is NULL, a new set is created and copied from @set2.
4042 * Doesn't chack for duplicate nodes. Clears set2.
4043 *
4044 * Returns @set1 once extended or NULL in case of error.
4045 */
4046static xmlNodeSetPtr
4047xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4048 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004049{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004050 if (set2 == NULL)
4051 return(set1);
4052 if ((set1 == NULL) && (hasNullEntries == 0)) {
4053 /*
4054 * Note that doing a memcpy of the list, namespace nodes are
4055 * just assigned to set1, since set2 is cleared anyway.
4056 */
4057 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4058 if (set1 == NULL)
4059 return(NULL);
4060 if (set2->nodeNr != 0) {
4061 memcpy(set1->nodeTab, set2->nodeTab,
4062 set2->nodeNr * sizeof(xmlNodePtr));
4063 set1->nodeNr = set2->nodeNr;
4064 }
4065 } else {
4066 int i;
4067 xmlNodePtr n2;
4068
4069 if (set1 == NULL)
4070 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004071 if (set1 == NULL)
4072 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004073
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004074 for (i = 0;i < set2->nodeNr;i++) {
4075 n2 = set2->nodeTab[i];
4076 /*
4077 * Skip NULLed entries.
4078 */
4079 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004080 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004081 if (set1->nodeMax == 0) {
4082 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4083 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4084 if (set1->nodeTab == NULL) {
4085 xmlXPathErrMemory(NULL, "merging nodeset\n");
4086 return(NULL);
4087 }
4088 memset(set1->nodeTab, 0,
4089 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4090 set1->nodeMax = XML_NODESET_DEFAULT;
4091 } else if (set1->nodeNr >= set1->nodeMax) {
4092 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004093
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004094 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4095 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4096 return(NULL);
4097 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004098 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004099 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004100 if (temp == NULL) {
4101 xmlXPathErrMemory(NULL, "merging nodeset\n");
4102 return(NULL);
4103 }
4104 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004105 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004106 }
4107 set1->nodeTab[set1->nodeNr++] = n2;
4108 }
4109 }
4110 set2->nodeNr = 0;
4111 return(set1);
4112}
Daniel Veillard75be0132002-03-13 10:03:35 +00004113
4114/**
Owen Taylor3473f882001-02-23 17:55:21 +00004115 * xmlXPathNodeSetDel:
4116 * @cur: the initial node set
4117 * @val: an xmlNodePtr
4118 *
4119 * Removes an xmlNodePtr from an existing NodeSet
4120 */
4121void
4122xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4123 int i;
4124
4125 if (cur == NULL) return;
4126 if (val == NULL) return;
4127
4128 /*
William M. Brack08171912003-12-29 02:52:11 +00004129 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004130 */
4131 for (i = 0;i < cur->nodeNr;i++)
4132 if (cur->nodeTab[i] == val) break;
4133
William M. Brack08171912003-12-29 02:52:11 +00004134 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004135#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004136 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004137 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4138 val->name);
4139#endif
4140 return;
4141 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004142 if ((cur->nodeTab[i] != NULL) &&
4143 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4144 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004145 cur->nodeNr--;
4146 for (;i < cur->nodeNr;i++)
4147 cur->nodeTab[i] = cur->nodeTab[i + 1];
4148 cur->nodeTab[cur->nodeNr] = NULL;
4149}
4150
4151/**
4152 * xmlXPathNodeSetRemove:
4153 * @cur: the initial node set
4154 * @val: the index to remove
4155 *
4156 * Removes an entry from an existing NodeSet list.
4157 */
4158void
4159xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4160 if (cur == NULL) return;
4161 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004162 if ((cur->nodeTab[val] != NULL) &&
4163 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4164 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004165 cur->nodeNr--;
4166 for (;val < cur->nodeNr;val++)
4167 cur->nodeTab[val] = cur->nodeTab[val + 1];
4168 cur->nodeTab[cur->nodeNr] = NULL;
4169}
4170
4171/**
4172 * xmlXPathFreeNodeSet:
4173 * @obj: the xmlNodeSetPtr to free
4174 *
4175 * Free the NodeSet compound (not the actual nodes !).
4176 */
4177void
4178xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4179 if (obj == NULL) return;
4180 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004181 int i;
4182
William M. Brack08171912003-12-29 02:52:11 +00004183 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004184 for (i = 0;i < obj->nodeNr;i++)
4185 if ((obj->nodeTab[i] != NULL) &&
4186 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4187 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004188 xmlFree(obj->nodeTab);
4189 }
Owen Taylor3473f882001-02-23 17:55:21 +00004190 xmlFree(obj);
4191}
4192
4193/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004194 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004195 * @set: the node set to clear
Daniel Veillard45490ae2008-07-29 09:13:19 +00004196 *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004197 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4198 * are feed), but does *not* free the list itself. Sets the length of the
4199 * list to 0.
4200 */
4201static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004202xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4203{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004204 if ((set == NULL) || (set->nodeNr <= 0))
4205 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004206 else if (hasNsNodes) {
4207 int i;
4208 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004209
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004210 for (i = 0; i < set->nodeNr; i++) {
4211 node = set->nodeTab[i];
4212 if ((node != NULL) &&
4213 (node->type == XML_NAMESPACE_DECL))
4214 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004215 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004216 }
4217 set->nodeNr = 0;
4218}
4219
4220/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004221 * xmlXPathNodeSetClearFromPos:
4222 * @set: the node set to be cleared
4223 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004224 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004225 * Clears the list from temporary XPath objects (e.g. namespace nodes
4226 * are feed) starting with the entry at @pos, but does *not* free the list
4227 * itself. Sets the length of the list to @pos.
4228 */
4229static void
4230xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4231{
4232 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4233 return;
4234 else if ((hasNsNodes)) {
4235 int i;
4236 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004237
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004238 for (i = pos; i < set->nodeNr; i++) {
4239 node = set->nodeTab[i];
4240 if ((node != NULL) &&
4241 (node->type == XML_NAMESPACE_DECL))
4242 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004243 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004244 }
4245 set->nodeNr = pos;
4246}
4247
4248/**
Owen Taylor3473f882001-02-23 17:55:21 +00004249 * xmlXPathFreeValueTree:
4250 * @obj: the xmlNodeSetPtr to free
4251 *
4252 * Free the NodeSet compound and the actual tree, this is different
4253 * from xmlXPathFreeNodeSet()
4254 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004255static void
Owen Taylor3473f882001-02-23 17:55:21 +00004256xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4257 int i;
4258
4259 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004260
4261 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004262 for (i = 0;i < obj->nodeNr;i++) {
4263 if (obj->nodeTab[i] != NULL) {
4264 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4265 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4266 } else {
4267 xmlFreeNodeList(obj->nodeTab[i]);
4268 }
4269 }
4270 }
Owen Taylor3473f882001-02-23 17:55:21 +00004271 xmlFree(obj->nodeTab);
4272 }
Owen Taylor3473f882001-02-23 17:55:21 +00004273 xmlFree(obj);
4274}
4275
4276#if defined(DEBUG) || defined(DEBUG_STEP)
4277/**
4278 * xmlGenericErrorContextNodeSet:
4279 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004280 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004281 *
4282 * Quick display of a NodeSet
4283 */
4284void
4285xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4286 int i;
4287
4288 if (output == NULL) output = xmlGenericErrorContext;
4289 if (obj == NULL) {
4290 fprintf(output, "NodeSet == NULL !\n");
4291 return;
4292 }
4293 if (obj->nodeNr == 0) {
4294 fprintf(output, "NodeSet is empty\n");
4295 return;
4296 }
4297 if (obj->nodeTab == NULL) {
4298 fprintf(output, " nodeTab == NULL !\n");
4299 return;
4300 }
4301 for (i = 0; i < obj->nodeNr; i++) {
4302 if (obj->nodeTab[i] == NULL) {
4303 fprintf(output, " NULL !\n");
4304 return;
4305 }
4306 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4307 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4308 fprintf(output, " /");
4309 else if (obj->nodeTab[i]->name == NULL)
4310 fprintf(output, " noname!");
4311 else fprintf(output, " %s", obj->nodeTab[i]->name);
4312 }
4313 fprintf(output, "\n");
4314}
4315#endif
4316
4317/**
4318 * xmlXPathNewNodeSet:
4319 * @val: the NodePtr value
4320 *
4321 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4322 * it with the single Node @val
4323 *
4324 * Returns the newly created object.
4325 */
4326xmlXPathObjectPtr
4327xmlXPathNewNodeSet(xmlNodePtr val) {
4328 xmlXPathObjectPtr ret;
4329
4330 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4331 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004332 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004333 return(NULL);
4334 }
4335 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4336 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004337 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004338 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004339 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004340#ifdef XP_DEBUG_OBJ_USAGE
4341 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4342#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004343 return(ret);
4344}
4345
4346/**
4347 * xmlXPathNewValueTree:
4348 * @val: the NodePtr value
4349 *
4350 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4351 * it with the tree root @val
4352 *
4353 * Returns the newly created object.
4354 */
4355xmlXPathObjectPtr
4356xmlXPathNewValueTree(xmlNodePtr val) {
4357 xmlXPathObjectPtr ret;
4358
4359 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4360 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004361 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004362 return(NULL);
4363 }
4364 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4365 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004366 ret->boolval = 1;
4367 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004368 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004369#ifdef XP_DEBUG_OBJ_USAGE
4370 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4371#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004372 return(ret);
4373}
4374
4375/**
4376 * xmlXPathNewNodeSetList:
4377 * @val: an existing NodeSet
4378 *
4379 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4380 * it with the Nodeset @val
4381 *
4382 * Returns the newly created object.
4383 */
4384xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004385xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4386{
Owen Taylor3473f882001-02-23 17:55:21 +00004387 xmlXPathObjectPtr ret;
4388 int i;
4389
4390 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004391 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004392 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004393 ret = xmlXPathNewNodeSet(NULL);
4394 else {
4395 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004396 if (ret) {
4397 for (i = 1; i < val->nodeNr; ++i) {
4398 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4399 < 0) break;
4400 }
4401 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004402 }
Owen Taylor3473f882001-02-23 17:55:21 +00004403
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004404 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004405}
4406
4407/**
4408 * xmlXPathWrapNodeSet:
4409 * @val: the NodePtr value
4410 *
4411 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4412 *
4413 * Returns the newly created object.
4414 */
4415xmlXPathObjectPtr
4416xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4417 xmlXPathObjectPtr ret;
4418
4419 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4420 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004421 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004422 return(NULL);
4423 }
4424 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4425 ret->type = XPATH_NODESET;
4426 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004427#ifdef XP_DEBUG_OBJ_USAGE
4428 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4429#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004430 return(ret);
4431}
4432
4433/**
4434 * xmlXPathFreeNodeSetList:
4435 * @obj: an existing NodeSetList object
4436 *
4437 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4438 * the list contrary to xmlXPathFreeObject().
4439 */
4440void
4441xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4442 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004443#ifdef XP_DEBUG_OBJ_USAGE
4444 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4445#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004446 xmlFree(obj);
4447}
4448
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004449/**
4450 * xmlXPathDifference:
4451 * @nodes1: a node-set
4452 * @nodes2: a node-set
4453 *
4454 * Implements the EXSLT - Sets difference() function:
4455 * node-set set:difference (node-set, node-set)
4456 *
4457 * Returns the difference between the two node sets, or nodes1 if
4458 * nodes2 is empty
4459 */
4460xmlNodeSetPtr
4461xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4462 xmlNodeSetPtr ret;
4463 int i, l1;
4464 xmlNodePtr cur;
4465
4466 if (xmlXPathNodeSetIsEmpty(nodes2))
4467 return(nodes1);
4468
4469 ret = xmlXPathNodeSetCreate(NULL);
4470 if (xmlXPathNodeSetIsEmpty(nodes1))
4471 return(ret);
4472
4473 l1 = xmlXPathNodeSetGetLength(nodes1);
4474
4475 for (i = 0; i < l1; i++) {
4476 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004477 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4478 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4479 break;
4480 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004481 }
4482 return(ret);
4483}
4484
4485/**
4486 * xmlXPathIntersection:
4487 * @nodes1: a node-set
4488 * @nodes2: a node-set
4489 *
4490 * Implements the EXSLT - Sets intersection() function:
4491 * node-set set:intersection (node-set, node-set)
4492 *
4493 * Returns a node set comprising the nodes that are within both the
4494 * node sets passed as arguments
4495 */
4496xmlNodeSetPtr
4497xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4498 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4499 int i, l1;
4500 xmlNodePtr cur;
4501
Daniel Veillardf88d8492008-04-01 08:00:31 +00004502 if (ret == NULL)
4503 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004504 if (xmlXPathNodeSetIsEmpty(nodes1))
4505 return(ret);
4506 if (xmlXPathNodeSetIsEmpty(nodes2))
4507 return(ret);
4508
4509 l1 = xmlXPathNodeSetGetLength(nodes1);
4510
4511 for (i = 0; i < l1; i++) {
4512 cur = xmlXPathNodeSetItem(nodes1, i);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004513 if (xmlXPathNodeSetContains(nodes2, cur)) {
4514 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4515 break;
4516 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004517 }
4518 return(ret);
4519}
4520
4521/**
4522 * xmlXPathDistinctSorted:
4523 * @nodes: a node-set, sorted by document order
4524 *
4525 * Implements the EXSLT - Sets distinct() function:
4526 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004527 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004528 * Returns a subset of the nodes contained in @nodes, or @nodes if
4529 * it is empty
4530 */
4531xmlNodeSetPtr
4532xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4533 xmlNodeSetPtr ret;
4534 xmlHashTablePtr hash;
4535 int i, l;
4536 xmlChar * strval;
4537 xmlNodePtr cur;
4538
4539 if (xmlXPathNodeSetIsEmpty(nodes))
4540 return(nodes);
4541
4542 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004543 if (ret == NULL)
4544 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004545 l = xmlXPathNodeSetGetLength(nodes);
4546 hash = xmlHashCreate (l);
4547 for (i = 0; i < l; i++) {
4548 cur = xmlXPathNodeSetItem(nodes, i);
4549 strval = xmlXPathCastNodeToString(cur);
4550 if (xmlHashLookup(hash, strval) == NULL) {
4551 xmlHashAddEntry(hash, strval, strval);
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004552 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4553 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004554 } else {
4555 xmlFree(strval);
4556 }
4557 }
4558 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4559 return(ret);
4560}
4561
4562/**
4563 * xmlXPathDistinct:
4564 * @nodes: a node-set
4565 *
4566 * Implements the EXSLT - Sets distinct() function:
4567 * node-set set:distinct (node-set)
4568 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4569 * is called with the sorted node-set
4570 *
4571 * Returns a subset of the nodes contained in @nodes, or @nodes if
4572 * it is empty
4573 */
4574xmlNodeSetPtr
4575xmlXPathDistinct (xmlNodeSetPtr nodes) {
4576 if (xmlXPathNodeSetIsEmpty(nodes))
4577 return(nodes);
4578
4579 xmlXPathNodeSetSort(nodes);
4580 return(xmlXPathDistinctSorted(nodes));
4581}
4582
4583/**
4584 * xmlXPathHasSameNodes:
4585 * @nodes1: a node-set
4586 * @nodes2: a node-set
4587 *
4588 * Implements the EXSLT - Sets has-same-nodes function:
4589 * boolean set:has-same-node(node-set, node-set)
4590 *
4591 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4592 * otherwise
4593 */
4594int
4595xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4596 int i, l;
4597 xmlNodePtr cur;
4598
4599 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4600 xmlXPathNodeSetIsEmpty(nodes2))
4601 return(0);
4602
4603 l = xmlXPathNodeSetGetLength(nodes1);
4604 for (i = 0; i < l; i++) {
4605 cur = xmlXPathNodeSetItem(nodes1, i);
4606 if (xmlXPathNodeSetContains(nodes2, cur))
4607 return(1);
4608 }
4609 return(0);
4610}
4611
4612/**
4613 * xmlXPathNodeLeadingSorted:
4614 * @nodes: a node-set, sorted by document order
4615 * @node: a node
4616 *
4617 * Implements the EXSLT - Sets leading() function:
4618 * node-set set:leading (node-set, node-set)
4619 *
4620 * Returns the nodes in @nodes that precede @node in document order,
4621 * @nodes if @node is NULL or an empty node-set if @nodes
4622 * doesn't contain @node
4623 */
4624xmlNodeSetPtr
4625xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4626 int i, l;
4627 xmlNodePtr cur;
4628 xmlNodeSetPtr ret;
4629
4630 if (node == NULL)
4631 return(nodes);
4632
4633 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004634 if (ret == NULL)
4635 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004636 if (xmlXPathNodeSetIsEmpty(nodes) ||
4637 (!xmlXPathNodeSetContains(nodes, node)))
4638 return(ret);
4639
4640 l = xmlXPathNodeSetGetLength(nodes);
4641 for (i = 0; i < l; i++) {
4642 cur = xmlXPathNodeSetItem(nodes, i);
4643 if (cur == node)
4644 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004645 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4646 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004647 }
4648 return(ret);
4649}
4650
4651/**
4652 * xmlXPathNodeLeading:
4653 * @nodes: a node-set
4654 * @node: a node
4655 *
4656 * Implements the EXSLT - Sets leading() function:
4657 * node-set set:leading (node-set, node-set)
4658 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4659 * is called.
4660 *
4661 * Returns the nodes in @nodes that precede @node in document order,
4662 * @nodes if @node is NULL or an empty node-set if @nodes
4663 * doesn't contain @node
4664 */
4665xmlNodeSetPtr
4666xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4667 xmlXPathNodeSetSort(nodes);
4668 return(xmlXPathNodeLeadingSorted(nodes, node));
4669}
4670
4671/**
4672 * xmlXPathLeadingSorted:
4673 * @nodes1: a node-set, sorted by document order
4674 * @nodes2: a node-set, sorted by document order
4675 *
4676 * Implements the EXSLT - Sets leading() function:
4677 * node-set set:leading (node-set, node-set)
4678 *
4679 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4680 * in document order, @nodes1 if @nodes2 is NULL or empty or
4681 * an empty node-set if @nodes1 doesn't contain @nodes2
4682 */
4683xmlNodeSetPtr
4684xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4685 if (xmlXPathNodeSetIsEmpty(nodes2))
4686 return(nodes1);
4687 return(xmlXPathNodeLeadingSorted(nodes1,
4688 xmlXPathNodeSetItem(nodes2, 1)));
4689}
4690
4691/**
4692 * xmlXPathLeading:
4693 * @nodes1: a node-set
4694 * @nodes2: a node-set
4695 *
4696 * Implements the EXSLT - Sets leading() function:
4697 * node-set set:leading (node-set, node-set)
4698 * @nodes1 and @nodes2 are sorted by document order, then
4699 * #exslSetsLeadingSorted is called.
4700 *
4701 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4702 * in document order, @nodes1 if @nodes2 is NULL or empty or
4703 * an empty node-set if @nodes1 doesn't contain @nodes2
4704 */
4705xmlNodeSetPtr
4706xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4707 if (xmlXPathNodeSetIsEmpty(nodes2))
4708 return(nodes1);
4709 if (xmlXPathNodeSetIsEmpty(nodes1))
4710 return(xmlXPathNodeSetCreate(NULL));
4711 xmlXPathNodeSetSort(nodes1);
4712 xmlXPathNodeSetSort(nodes2);
4713 return(xmlXPathNodeLeadingSorted(nodes1,
4714 xmlXPathNodeSetItem(nodes2, 1)));
4715}
4716
4717/**
4718 * xmlXPathNodeTrailingSorted:
4719 * @nodes: a node-set, sorted by document order
4720 * @node: a node
4721 *
4722 * Implements the EXSLT - Sets trailing() function:
4723 * node-set set:trailing (node-set, node-set)
4724 *
4725 * Returns the nodes in @nodes that follow @node in document order,
4726 * @nodes if @node is NULL or an empty node-set if @nodes
4727 * doesn't contain @node
4728 */
4729xmlNodeSetPtr
4730xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4731 int i, l;
4732 xmlNodePtr cur;
4733 xmlNodeSetPtr ret;
4734
4735 if (node == NULL)
4736 return(nodes);
4737
4738 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004739 if (ret == NULL)
4740 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004741 if (xmlXPathNodeSetIsEmpty(nodes) ||
4742 (!xmlXPathNodeSetContains(nodes, node)))
4743 return(ret);
4744
4745 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004746 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004747 cur = xmlXPathNodeSetItem(nodes, i);
4748 if (cur == node)
4749 break;
Daniel Veillard1bd45d12012-09-05 15:35:19 +08004750 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4751 break;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004752 }
William M. Brack97ac8192007-06-06 17:19:24 +00004753 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004754 return(ret);
4755}
4756
4757/**
4758 * xmlXPathNodeTrailing:
4759 * @nodes: a node-set
4760 * @node: a node
4761 *
4762 * Implements the EXSLT - Sets trailing() function:
4763 * node-set set:trailing (node-set, node-set)
4764 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4765 * is called.
4766 *
4767 * Returns the nodes in @nodes that follow @node in document order,
4768 * @nodes if @node is NULL or an empty node-set if @nodes
4769 * doesn't contain @node
4770 */
4771xmlNodeSetPtr
4772xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4773 xmlXPathNodeSetSort(nodes);
4774 return(xmlXPathNodeTrailingSorted(nodes, node));
4775}
4776
4777/**
4778 * xmlXPathTrailingSorted:
4779 * @nodes1: a node-set, sorted by document order
4780 * @nodes2: a node-set, sorted by document order
4781 *
4782 * Implements the EXSLT - Sets trailing() function:
4783 * node-set set:trailing (node-set, node-set)
4784 *
4785 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4786 * in document order, @nodes1 if @nodes2 is NULL or empty or
4787 * an empty node-set if @nodes1 doesn't contain @nodes2
4788 */
4789xmlNodeSetPtr
4790xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4791 if (xmlXPathNodeSetIsEmpty(nodes2))
4792 return(nodes1);
4793 return(xmlXPathNodeTrailingSorted(nodes1,
4794 xmlXPathNodeSetItem(nodes2, 0)));
4795}
4796
4797/**
4798 * xmlXPathTrailing:
4799 * @nodes1: a node-set
4800 * @nodes2: a node-set
4801 *
4802 * Implements the EXSLT - Sets trailing() function:
4803 * node-set set:trailing (node-set, node-set)
4804 * @nodes1 and @nodes2 are sorted by document order, then
4805 * #xmlXPathTrailingSorted is called.
4806 *
4807 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4808 * in document order, @nodes1 if @nodes2 is NULL or empty or
4809 * an empty node-set if @nodes1 doesn't contain @nodes2
4810 */
4811xmlNodeSetPtr
4812xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4813 if (xmlXPathNodeSetIsEmpty(nodes2))
4814 return(nodes1);
4815 if (xmlXPathNodeSetIsEmpty(nodes1))
4816 return(xmlXPathNodeSetCreate(NULL));
4817 xmlXPathNodeSetSort(nodes1);
4818 xmlXPathNodeSetSort(nodes2);
4819 return(xmlXPathNodeTrailingSorted(nodes1,
4820 xmlXPathNodeSetItem(nodes2, 0)));
4821}
4822
Owen Taylor3473f882001-02-23 17:55:21 +00004823/************************************************************************
4824 * *
4825 * Routines to handle extra functions *
4826 * *
4827 ************************************************************************/
4828
4829/**
4830 * xmlXPathRegisterFunc:
4831 * @ctxt: the XPath context
4832 * @name: the function name
4833 * @f: the function implementation or NULL
4834 *
4835 * Register a new function. If @f is NULL it unregisters the function
4836 *
4837 * Returns 0 in case of success, -1 in case of error
4838 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004839int
Owen Taylor3473f882001-02-23 17:55:21 +00004840xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4841 xmlXPathFunction f) {
4842 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4843}
4844
4845/**
4846 * xmlXPathRegisterFuncNS:
4847 * @ctxt: the XPath context
4848 * @name: the function name
4849 * @ns_uri: the function namespace URI
4850 * @f: the function implementation or NULL
4851 *
4852 * Register a new function. If @f is NULL it unregisters the function
4853 *
4854 * Returns 0 in case of success, -1 in case of error
4855 */
4856int
4857xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4858 const xmlChar *ns_uri, xmlXPathFunction f) {
4859 if (ctxt == NULL)
4860 return(-1);
4861 if (name == NULL)
4862 return(-1);
4863
4864 if (ctxt->funcHash == NULL)
4865 ctxt->funcHash = xmlHashCreate(0);
4866 if (ctxt->funcHash == NULL)
4867 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004868 if (f == NULL)
4869 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004870 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004871}
4872
4873/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004874 * xmlXPathRegisterFuncLookup:
4875 * @ctxt: the XPath context
4876 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004877 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004878 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004879 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004880 */
4881void
4882xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4883 xmlXPathFuncLookupFunc f,
4884 void *funcCtxt) {
4885 if (ctxt == NULL)
4886 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004887 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004888 ctxt->funcLookupData = funcCtxt;
4889}
4890
4891/**
Owen Taylor3473f882001-02-23 17:55:21 +00004892 * xmlXPathFunctionLookup:
4893 * @ctxt: the XPath context
4894 * @name: the function name
4895 *
4896 * Search in the Function array of the context for the given
4897 * function.
4898 *
4899 * Returns the xmlXPathFunction or NULL if not found
4900 */
4901xmlXPathFunction
4902xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004903 if (ctxt == NULL)
4904 return (NULL);
4905
4906 if (ctxt->funcLookupFunc != NULL) {
4907 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004908 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004909
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004910 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004911 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004912 if (ret != NULL)
4913 return(ret);
4914 }
Owen Taylor3473f882001-02-23 17:55:21 +00004915 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4916}
4917
4918/**
4919 * xmlXPathFunctionLookupNS:
4920 * @ctxt: the XPath context
4921 * @name: the function name
4922 * @ns_uri: the function namespace URI
4923 *
4924 * Search in the Function array of the context for the given
4925 * function.
4926 *
4927 * Returns the xmlXPathFunction or NULL if not found
4928 */
4929xmlXPathFunction
4930xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4931 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004932 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004933
Owen Taylor3473f882001-02-23 17:55:21 +00004934 if (ctxt == NULL)
4935 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004936 if (name == NULL)
4937 return(NULL);
4938
Thomas Broyerba4ad322001-07-26 16:55:21 +00004939 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004940 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004941
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004942 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004943 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004944 if (ret != NULL)
4945 return(ret);
4946 }
4947
4948 if (ctxt->funcHash == NULL)
4949 return(NULL);
4950
William M. Brackad0e67c2004-12-01 14:35:10 +00004951 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4952 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004953}
4954
4955/**
4956 * xmlXPathRegisteredFuncsCleanup:
4957 * @ctxt: the XPath context
4958 *
4959 * Cleanup the XPath context data associated to registered functions
4960 */
4961void
4962xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4963 if (ctxt == NULL)
4964 return;
4965
4966 xmlHashFree(ctxt->funcHash, NULL);
4967 ctxt->funcHash = NULL;
4968}
4969
4970/************************************************************************
4971 * *
William M. Brack08171912003-12-29 02:52:11 +00004972 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004973 * *
4974 ************************************************************************/
4975
4976/**
4977 * xmlXPathRegisterVariable:
4978 * @ctxt: the XPath context
4979 * @name: the variable name
4980 * @value: the variable value or NULL
4981 *
4982 * Register a new variable value. If @value is NULL it unregisters
4983 * the variable
4984 *
4985 * Returns 0 in case of success, -1 in case of error
4986 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004987int
Owen Taylor3473f882001-02-23 17:55:21 +00004988xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4989 xmlXPathObjectPtr value) {
4990 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4991}
4992
4993/**
4994 * xmlXPathRegisterVariableNS:
4995 * @ctxt: the XPath context
4996 * @name: the variable name
4997 * @ns_uri: the variable namespace URI
4998 * @value: the variable value or NULL
4999 *
5000 * Register a new variable value. If @value is NULL it unregisters
5001 * the variable
5002 *
5003 * Returns 0 in case of success, -1 in case of error
5004 */
5005int
5006xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5007 const xmlChar *ns_uri,
5008 xmlXPathObjectPtr value) {
5009 if (ctxt == NULL)
5010 return(-1);
5011 if (name == NULL)
5012 return(-1);
5013
5014 if (ctxt->varHash == NULL)
5015 ctxt->varHash = xmlHashCreate(0);
5016 if (ctxt->varHash == NULL)
5017 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00005018 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005019 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00005020 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00005021 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5022 (void *) value,
5023 (xmlHashDeallocator)xmlXPathFreeObject));
5024}
5025
5026/**
5027 * xmlXPathRegisterVariableLookup:
5028 * @ctxt: the XPath context
5029 * @f: the lookup function
5030 * @data: the lookup data
5031 *
5032 * register an external mechanism to do variable lookup
5033 */
5034void
5035xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5036 xmlXPathVariableLookupFunc f, void *data) {
5037 if (ctxt == NULL)
5038 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00005039 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00005040 ctxt->varLookupData = data;
5041}
5042
5043/**
5044 * xmlXPathVariableLookup:
5045 * @ctxt: the XPath context
5046 * @name: the variable name
5047 *
5048 * Search in the Variable array of the context for the given
5049 * variable value.
5050 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005051 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005052 */
5053xmlXPathObjectPtr
5054xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5055 if (ctxt == NULL)
5056 return(NULL);
5057
5058 if (ctxt->varLookupFunc != NULL) {
5059 xmlXPathObjectPtr ret;
5060
5061 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5062 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00005063 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005064 }
5065 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5066}
5067
5068/**
5069 * xmlXPathVariableLookupNS:
5070 * @ctxt: the XPath context
5071 * @name: the variable name
5072 * @ns_uri: the variable namespace URI
5073 *
5074 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005075 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005076 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005077 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005078 */
5079xmlXPathObjectPtr
5080xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5081 const xmlChar *ns_uri) {
5082 if (ctxt == NULL)
5083 return(NULL);
5084
5085 if (ctxt->varLookupFunc != NULL) {
5086 xmlXPathObjectPtr ret;
5087
5088 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5089 (ctxt->varLookupData, name, ns_uri);
5090 if (ret != NULL) return(ret);
5091 }
5092
5093 if (ctxt->varHash == NULL)
5094 return(NULL);
5095 if (name == NULL)
5096 return(NULL);
5097
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005098 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005099 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005100}
5101
5102/**
5103 * xmlXPathRegisteredVariablesCleanup:
5104 * @ctxt: the XPath context
5105 *
5106 * Cleanup the XPath context data associated to registered variables
5107 */
5108void
5109xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5110 if (ctxt == NULL)
5111 return;
5112
Daniel Veillard76d66f42001-05-16 21:05:17 +00005113 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005114 ctxt->varHash = NULL;
5115}
5116
5117/**
5118 * xmlXPathRegisterNs:
5119 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005120 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005121 * @ns_uri: the namespace name
5122 *
5123 * Register a new namespace. If @ns_uri is NULL it unregisters
5124 * the namespace
5125 *
5126 * Returns 0 in case of success, -1 in case of error
5127 */
5128int
5129xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5130 const xmlChar *ns_uri) {
5131 if (ctxt == NULL)
5132 return(-1);
5133 if (prefix == NULL)
5134 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005135 if (prefix[0] == 0)
5136 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005137
5138 if (ctxt->nsHash == NULL)
5139 ctxt->nsHash = xmlHashCreate(10);
5140 if (ctxt->nsHash == NULL)
5141 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005142 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005143 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005144 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005145 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005146 (xmlHashDeallocator)xmlFree));
5147}
5148
5149/**
5150 * xmlXPathNsLookup:
5151 * @ctxt: the XPath context
5152 * @prefix: the namespace prefix value
5153 *
5154 * Search in the namespace declaration array of the context for the given
5155 * namespace name associated to the given prefix
5156 *
5157 * Returns the value or NULL if not found
5158 */
5159const xmlChar *
5160xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5161 if (ctxt == NULL)
5162 return(NULL);
5163 if (prefix == NULL)
5164 return(NULL);
5165
5166#ifdef XML_XML_NAMESPACE
5167 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5168 return(XML_XML_NAMESPACE);
5169#endif
5170
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005171 if (ctxt->namespaces != NULL) {
5172 int i;
5173
5174 for (i = 0;i < ctxt->nsNr;i++) {
5175 if ((ctxt->namespaces[i] != NULL) &&
5176 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5177 return(ctxt->namespaces[i]->href);
5178 }
5179 }
Owen Taylor3473f882001-02-23 17:55:21 +00005180
5181 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5182}
5183
5184/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005185 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005186 * @ctxt: the XPath context
5187 *
5188 * Cleanup the XPath context data associated to registered variables
5189 */
5190void
5191xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5192 if (ctxt == NULL)
5193 return;
5194
Daniel Veillard42766c02002-08-22 20:52:17 +00005195 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005196 ctxt->nsHash = NULL;
5197}
5198
5199/************************************************************************
5200 * *
5201 * Routines to handle Values *
5202 * *
5203 ************************************************************************/
5204
William M. Brack08171912003-12-29 02:52:11 +00005205/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005206
5207/**
5208 * xmlXPathNewFloat:
5209 * @val: the double value
5210 *
5211 * Create a new xmlXPathObjectPtr of type double and of value @val
5212 *
5213 * Returns the newly created object.
5214 */
5215xmlXPathObjectPtr
5216xmlXPathNewFloat(double val) {
5217 xmlXPathObjectPtr ret;
5218
5219 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5220 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005221 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005222 return(NULL);
5223 }
5224 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5225 ret->type = XPATH_NUMBER;
5226 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005227#ifdef XP_DEBUG_OBJ_USAGE
5228 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5229#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005230 return(ret);
5231}
5232
5233/**
5234 * xmlXPathNewBoolean:
5235 * @val: the boolean value
5236 *
5237 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5238 *
5239 * Returns the newly created object.
5240 */
5241xmlXPathObjectPtr
5242xmlXPathNewBoolean(int val) {
5243 xmlXPathObjectPtr ret;
5244
5245 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5246 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005247 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005248 return(NULL);
5249 }
5250 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5251 ret->type = XPATH_BOOLEAN;
5252 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005253#ifdef XP_DEBUG_OBJ_USAGE
5254 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5255#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005256 return(ret);
5257}
5258
5259/**
5260 * xmlXPathNewString:
5261 * @val: the xmlChar * value
5262 *
5263 * Create a new xmlXPathObjectPtr of type string and of value @val
5264 *
5265 * Returns the newly created object.
5266 */
5267xmlXPathObjectPtr
5268xmlXPathNewString(const xmlChar *val) {
5269 xmlXPathObjectPtr ret;
5270
5271 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5272 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005273 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005274 return(NULL);
5275 }
5276 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5277 ret->type = XPATH_STRING;
5278 if (val != NULL)
5279 ret->stringval = xmlStrdup(val);
5280 else
5281 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005282#ifdef XP_DEBUG_OBJ_USAGE
5283 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5284#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005285 return(ret);
5286}
5287
5288/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005289 * xmlXPathWrapString:
5290 * @val: the xmlChar * value
5291 *
5292 * Wraps the @val string into an XPath object.
5293 *
5294 * Returns the newly created object.
5295 */
5296xmlXPathObjectPtr
5297xmlXPathWrapString (xmlChar *val) {
5298 xmlXPathObjectPtr ret;
5299
5300 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5301 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005302 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005303 return(NULL);
5304 }
5305 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5306 ret->type = XPATH_STRING;
5307 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005308#ifdef XP_DEBUG_OBJ_USAGE
5309 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5310#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005311 return(ret);
5312}
5313
5314/**
Owen Taylor3473f882001-02-23 17:55:21 +00005315 * xmlXPathNewCString:
5316 * @val: the char * value
5317 *
5318 * Create a new xmlXPathObjectPtr of type string and of value @val
5319 *
5320 * Returns the newly created object.
5321 */
5322xmlXPathObjectPtr
5323xmlXPathNewCString(const char *val) {
5324 xmlXPathObjectPtr ret;
5325
5326 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5327 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005328 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005329 return(NULL);
5330 }
5331 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5332 ret->type = XPATH_STRING;
5333 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005334#ifdef XP_DEBUG_OBJ_USAGE
5335 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5336#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005337 return(ret);
5338}
5339
5340/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005341 * xmlXPathWrapCString:
5342 * @val: the char * value
5343 *
5344 * Wraps a string into an XPath object.
5345 *
5346 * Returns the newly created object.
5347 */
5348xmlXPathObjectPtr
5349xmlXPathWrapCString (char * val) {
5350 return(xmlXPathWrapString((xmlChar *)(val)));
5351}
5352
5353/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005354 * xmlXPathWrapExternal:
5355 * @val: the user data
5356 *
5357 * Wraps the @val data into an XPath object.
5358 *
5359 * Returns the newly created object.
5360 */
5361xmlXPathObjectPtr
5362xmlXPathWrapExternal (void *val) {
5363 xmlXPathObjectPtr ret;
5364
5365 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5366 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005367 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005368 return(NULL);
5369 }
5370 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5371 ret->type = XPATH_USERS;
5372 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005373#ifdef XP_DEBUG_OBJ_USAGE
5374 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5375#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005376 return(ret);
5377}
5378
5379/**
Owen Taylor3473f882001-02-23 17:55:21 +00005380 * xmlXPathObjectCopy:
5381 * @val: the original object
5382 *
5383 * allocate a new copy of a given object
5384 *
5385 * Returns the newly created object.
5386 */
5387xmlXPathObjectPtr
5388xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5389 xmlXPathObjectPtr ret;
5390
5391 if (val == NULL)
5392 return(NULL);
5393
5394 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5395 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005396 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005397 return(NULL);
5398 }
5399 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005400#ifdef XP_DEBUG_OBJ_USAGE
5401 xmlXPathDebugObjUsageRequested(NULL, val->type);
5402#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005403 switch (val->type) {
5404 case XPATH_BOOLEAN:
5405 case XPATH_NUMBER:
5406 case XPATH_POINT:
5407 case XPATH_RANGE:
5408 break;
5409 case XPATH_STRING:
5410 ret->stringval = xmlStrdup(val->stringval);
5411 break;
5412 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005413#if 0
5414/*
5415 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5416 this previous handling is no longer correct, and can cause some serious
5417 problems (ref. bug 145547)
5418*/
Owen Taylor3473f882001-02-23 17:55:21 +00005419 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005420 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005421 xmlNodePtr cur, tmp;
5422 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005423
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005424 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005425 top = xmlNewDoc(NULL);
5426 top->name = (char *)
5427 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005428 ret->user = top;
5429 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005430 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005431 cur = val->nodesetval->nodeTab[0]->children;
5432 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005433 tmp = xmlDocCopyNode(cur, top, 1);
5434 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005435 cur = cur->next;
5436 }
5437 }
William M. Bracke9449c52004-07-11 14:41:20 +00005438
Daniel Veillard9adc0462003-03-24 18:39:54 +00005439 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005440 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005441 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005442 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005443 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005444#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005445 case XPATH_NODESET:
5446 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005447 /* Do not deallocate the copied tree value */
5448 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005449 break;
5450 case XPATH_LOCATIONSET:
5451#ifdef LIBXML_XPTR_ENABLED
5452 {
5453 xmlLocationSetPtr loc = val->user;
5454 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5455 break;
5456 }
5457#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005458 case XPATH_USERS:
5459 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005460 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005461 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005462 xmlGenericError(xmlGenericErrorContext,
5463 "xmlXPathObjectCopy: unsupported type %d\n",
5464 val->type);
5465 break;
5466 }
5467 return(ret);
5468}
5469
5470/**
5471 * xmlXPathFreeObject:
5472 * @obj: the object to free
5473 *
5474 * Free up an xmlXPathObjectPtr object.
5475 */
5476void
5477xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5478 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005479 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005480 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005481#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005482 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005483 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005484 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005485 } else
5486#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005487 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005488 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005489 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005490 } else {
5491 if (obj->nodesetval != NULL)
5492 xmlXPathFreeNodeSet(obj->nodesetval);
5493 }
Owen Taylor3473f882001-02-23 17:55:21 +00005494#ifdef LIBXML_XPTR_ENABLED
5495 } else if (obj->type == XPATH_LOCATIONSET) {
5496 if (obj->user != NULL)
5497 xmlXPtrFreeLocationSet(obj->user);
5498#endif
5499 } else if (obj->type == XPATH_STRING) {
5500 if (obj->stringval != NULL)
5501 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005502 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005503#ifdef XP_DEBUG_OBJ_USAGE
5504 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5505#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005506 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005507}
Owen Taylor3473f882001-02-23 17:55:21 +00005508
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005509/**
5510 * xmlXPathReleaseObject:
5511 * @obj: the xmlXPathObjectPtr to free or to cache
5512 *
5513 * Depending on the state of the cache this frees the given
5514 * XPath object or stores it in the cache.
5515 */
5516static void
5517xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5518{
5519#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5520 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5521 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5522
5523#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5524
5525 if (obj == NULL)
5526 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005527 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005528 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005529 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005530 xmlXPathContextCachePtr cache =
5531 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005532
5533 switch (obj->type) {
5534 case XPATH_NODESET:
5535 case XPATH_XSLT_TREE:
5536 if (obj->nodesetval != NULL) {
5537 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005538 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005539 * It looks like the @boolval is used for
5540 * evaluation if this an XSLT Result Tree Fragment.
5541 * TODO: Check if this assumption is correct.
5542 */
5543 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5544 xmlXPathFreeValueTree(obj->nodesetval);
5545 obj->nodesetval = NULL;
5546 } else if ((obj->nodesetval->nodeMax <= 40) &&
5547 (XP_CACHE_WANTS(cache->nodesetObjs,
5548 cache->maxNodeset)))
5549 {
5550 XP_CACHE_ADD(cache->nodesetObjs, obj);
5551 goto obj_cached;
5552 } else {
5553 xmlXPathFreeNodeSet(obj->nodesetval);
5554 obj->nodesetval = NULL;
5555 }
5556 }
5557 break;
5558 case XPATH_STRING:
5559 if (obj->stringval != NULL)
5560 xmlFree(obj->stringval);
5561
5562 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5563 XP_CACHE_ADD(cache->stringObjs, obj);
5564 goto obj_cached;
5565 }
5566 break;
5567 case XPATH_BOOLEAN:
5568 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5569 XP_CACHE_ADD(cache->booleanObjs, obj);
5570 goto obj_cached;
5571 }
5572 break;
5573 case XPATH_NUMBER:
5574 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5575 XP_CACHE_ADD(cache->numberObjs, obj);
5576 goto obj_cached;
5577 }
5578 break;
5579#ifdef LIBXML_XPTR_ENABLED
5580 case XPATH_LOCATIONSET:
5581 if (obj->user != NULL) {
5582 xmlXPtrFreeLocationSet(obj->user);
5583 }
5584 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005585#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005586 default:
5587 goto free_obj;
5588 }
5589
5590 /*
5591 * Fallback to adding to the misc-objects slot.
5592 */
5593 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5594 XP_CACHE_ADD(cache->miscObjs, obj);
5595 } else
5596 goto free_obj;
5597
5598obj_cached:
5599
5600#ifdef XP_DEBUG_OBJ_USAGE
5601 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5602#endif
5603
5604 if (obj->nodesetval != NULL) {
5605 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005606
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005607 /*
5608 * TODO: Due to those nasty ns-nodes, we need to traverse
5609 * the list and free the ns-nodes.
5610 * URGENT TODO: Check if it's actually slowing things down.
5611 * Maybe we shouldn't try to preserve the list.
5612 */
5613 if (tmpset->nodeNr > 1) {
5614 int i;
5615 xmlNodePtr node;
5616
5617 for (i = 0; i < tmpset->nodeNr; i++) {
5618 node = tmpset->nodeTab[i];
5619 if ((node != NULL) &&
5620 (node->type == XML_NAMESPACE_DECL))
5621 {
5622 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5623 }
5624 }
5625 } else if (tmpset->nodeNr == 1) {
5626 if ((tmpset->nodeTab[0] != NULL) &&
5627 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5628 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005629 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005630 tmpset->nodeNr = 0;
5631 memset(obj, 0, sizeof(xmlXPathObject));
5632 obj->nodesetval = tmpset;
5633 } else
5634 memset(obj, 0, sizeof(xmlXPathObject));
5635
5636 return;
5637
5638free_obj:
5639 /*
5640 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005641 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005642 if (obj->nodesetval != NULL)
5643 xmlXPathFreeNodeSet(obj->nodesetval);
5644#ifdef XP_DEBUG_OBJ_USAGE
5645 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5646#endif
5647 xmlFree(obj);
5648 }
5649 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005650}
5651
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005652
5653/************************************************************************
5654 * *
5655 * Type Casting Routines *
5656 * *
5657 ************************************************************************/
5658
5659/**
5660 * xmlXPathCastBooleanToString:
5661 * @val: a boolean
5662 *
5663 * Converts a boolean to its string value.
5664 *
5665 * Returns a newly allocated string.
5666 */
5667xmlChar *
5668xmlXPathCastBooleanToString (int val) {
5669 xmlChar *ret;
5670 if (val)
5671 ret = xmlStrdup((const xmlChar *) "true");
5672 else
5673 ret = xmlStrdup((const xmlChar *) "false");
5674 return(ret);
5675}
5676
5677/**
5678 * xmlXPathCastNumberToString:
5679 * @val: a number
5680 *
5681 * Converts a number to its string value.
5682 *
5683 * Returns a newly allocated string.
5684 */
5685xmlChar *
5686xmlXPathCastNumberToString (double val) {
5687 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005688 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005689 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005690 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005691 break;
5692 case -1:
5693 ret = xmlStrdup((const xmlChar *) "-Infinity");
5694 break;
5695 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005696 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005697 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005698 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5699 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005700 } else {
5701 /* could be improved */
5702 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005703 xmlXPathFormatNumber(val, buf, 99);
5704 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005705 ret = xmlStrdup((const xmlChar *) buf);
5706 }
5707 }
5708 return(ret);
5709}
5710
5711/**
5712 * xmlXPathCastNodeToString:
5713 * @node: a node
5714 *
5715 * Converts a node to its string value.
5716 *
5717 * Returns a newly allocated string.
5718 */
5719xmlChar *
5720xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005721xmlChar *ret;
5722 if ((ret = xmlNodeGetContent(node)) == NULL)
5723 ret = xmlStrdup((const xmlChar *) "");
5724 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005725}
5726
5727/**
5728 * xmlXPathCastNodeSetToString:
5729 * @ns: a node-set
5730 *
5731 * Converts a node-set to its string value.
5732 *
5733 * Returns a newly allocated string.
5734 */
5735xmlChar *
5736xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5737 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5738 return(xmlStrdup((const xmlChar *) ""));
5739
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005740 if (ns->nodeNr > 1)
5741 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005742 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5743}
5744
5745/**
5746 * xmlXPathCastToString:
5747 * @val: an XPath object
5748 *
5749 * Converts an existing object to its string() equivalent
5750 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005751 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005752 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005753 */
5754xmlChar *
5755xmlXPathCastToString(xmlXPathObjectPtr val) {
5756 xmlChar *ret = NULL;
5757
5758 if (val == NULL)
5759 return(xmlStrdup((const xmlChar *) ""));
5760 switch (val->type) {
5761 case XPATH_UNDEFINED:
5762#ifdef DEBUG_EXPR
5763 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5764#endif
5765 ret = xmlStrdup((const xmlChar *) "");
5766 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005767 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005768 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005769 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5770 break;
5771 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005772 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005773 case XPATH_BOOLEAN:
5774 ret = xmlXPathCastBooleanToString(val->boolval);
5775 break;
5776 case XPATH_NUMBER: {
5777 ret = xmlXPathCastNumberToString(val->floatval);
5778 break;
5779 }
5780 case XPATH_USERS:
5781 case XPATH_POINT:
5782 case XPATH_RANGE:
5783 case XPATH_LOCATIONSET:
5784 TODO
5785 ret = xmlStrdup((const xmlChar *) "");
5786 break;
5787 }
5788 return(ret);
5789}
5790
5791/**
5792 * xmlXPathConvertString:
5793 * @val: an XPath object
5794 *
5795 * Converts an existing object to its string() equivalent
5796 *
5797 * Returns the new object, the old one is freed (or the operation
5798 * is done directly on @val)
5799 */
5800xmlXPathObjectPtr
5801xmlXPathConvertString(xmlXPathObjectPtr val) {
5802 xmlChar *res = NULL;
5803
5804 if (val == NULL)
5805 return(xmlXPathNewCString(""));
5806
5807 switch (val->type) {
5808 case XPATH_UNDEFINED:
5809#ifdef DEBUG_EXPR
5810 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5811#endif
5812 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005813 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005814 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005815 res = xmlXPathCastNodeSetToString(val->nodesetval);
5816 break;
5817 case XPATH_STRING:
5818 return(val);
5819 case XPATH_BOOLEAN:
5820 res = xmlXPathCastBooleanToString(val->boolval);
5821 break;
5822 case XPATH_NUMBER:
5823 res = xmlXPathCastNumberToString(val->floatval);
5824 break;
5825 case XPATH_USERS:
5826 case XPATH_POINT:
5827 case XPATH_RANGE:
5828 case XPATH_LOCATIONSET:
5829 TODO;
5830 break;
5831 }
5832 xmlXPathFreeObject(val);
5833 if (res == NULL)
5834 return(xmlXPathNewCString(""));
5835 return(xmlXPathWrapString(res));
5836}
5837
5838/**
5839 * xmlXPathCastBooleanToNumber:
5840 * @val: a boolean
5841 *
5842 * Converts a boolean to its number value
5843 *
5844 * Returns the number value
5845 */
5846double
5847xmlXPathCastBooleanToNumber(int val) {
5848 if (val)
5849 return(1.0);
5850 return(0.0);
5851}
5852
5853/**
5854 * xmlXPathCastStringToNumber:
5855 * @val: a string
5856 *
5857 * Converts a string to its number value
5858 *
5859 * Returns the number value
5860 */
5861double
5862xmlXPathCastStringToNumber(const xmlChar * val) {
5863 return(xmlXPathStringEvalNumber(val));
5864}
5865
5866/**
5867 * xmlXPathCastNodeToNumber:
5868 * @node: a node
5869 *
5870 * Converts a node to its number value
5871 *
5872 * Returns the number value
5873 */
5874double
5875xmlXPathCastNodeToNumber (xmlNodePtr node) {
5876 xmlChar *strval;
5877 double ret;
5878
5879 if (node == NULL)
5880 return(xmlXPathNAN);
5881 strval = xmlXPathCastNodeToString(node);
5882 if (strval == NULL)
5883 return(xmlXPathNAN);
5884 ret = xmlXPathCastStringToNumber(strval);
5885 xmlFree(strval);
5886
5887 return(ret);
5888}
5889
5890/**
5891 * xmlXPathCastNodeSetToNumber:
5892 * @ns: a node-set
5893 *
5894 * Converts a node-set to its number value
5895 *
5896 * Returns the number value
5897 */
5898double
5899xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5900 xmlChar *str;
5901 double ret;
5902
5903 if (ns == NULL)
5904 return(xmlXPathNAN);
5905 str = xmlXPathCastNodeSetToString(ns);
5906 ret = xmlXPathCastStringToNumber(str);
5907 xmlFree(str);
5908 return(ret);
5909}
5910
5911/**
5912 * xmlXPathCastToNumber:
5913 * @val: an XPath object
5914 *
5915 * Converts an XPath object to its number value
5916 *
5917 * Returns the number value
5918 */
5919double
5920xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5921 double ret = 0.0;
5922
5923 if (val == NULL)
5924 return(xmlXPathNAN);
5925 switch (val->type) {
5926 case XPATH_UNDEFINED:
5927#ifdef DEGUB_EXPR
5928 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5929#endif
5930 ret = xmlXPathNAN;
5931 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005932 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005933 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005934 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5935 break;
5936 case XPATH_STRING:
5937 ret = xmlXPathCastStringToNumber(val->stringval);
5938 break;
5939 case XPATH_NUMBER:
5940 ret = val->floatval;
5941 break;
5942 case XPATH_BOOLEAN:
5943 ret = xmlXPathCastBooleanToNumber(val->boolval);
5944 break;
5945 case XPATH_USERS:
5946 case XPATH_POINT:
5947 case XPATH_RANGE:
5948 case XPATH_LOCATIONSET:
5949 TODO;
5950 ret = xmlXPathNAN;
5951 break;
5952 }
5953 return(ret);
5954}
5955
5956/**
5957 * xmlXPathConvertNumber:
5958 * @val: an XPath object
5959 *
5960 * Converts an existing object to its number() equivalent
5961 *
5962 * Returns the new object, the old one is freed (or the operation
5963 * is done directly on @val)
5964 */
5965xmlXPathObjectPtr
5966xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5967 xmlXPathObjectPtr ret;
5968
5969 if (val == NULL)
5970 return(xmlXPathNewFloat(0.0));
5971 if (val->type == XPATH_NUMBER)
5972 return(val);
5973 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5974 xmlXPathFreeObject(val);
5975 return(ret);
5976}
5977
5978/**
5979 * xmlXPathCastNumberToBoolean:
5980 * @val: a number
5981 *
5982 * Converts a number to its boolean value
5983 *
5984 * Returns the boolean value
5985 */
5986int
5987xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005988 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005989 return(0);
5990 return(1);
5991}
5992
5993/**
5994 * xmlXPathCastStringToBoolean:
5995 * @val: a string
5996 *
5997 * Converts a string to its boolean value
5998 *
5999 * Returns the boolean value
6000 */
6001int
6002xmlXPathCastStringToBoolean (const xmlChar *val) {
6003 if ((val == NULL) || (xmlStrlen(val) == 0))
6004 return(0);
6005 return(1);
6006}
6007
6008/**
6009 * xmlXPathCastNodeSetToBoolean:
6010 * @ns: a node-set
6011 *
6012 * Converts a node-set to its boolean value
6013 *
6014 * Returns the boolean value
6015 */
6016int
6017xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6018 if ((ns == NULL) || (ns->nodeNr == 0))
6019 return(0);
6020 return(1);
6021}
6022
6023/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00006024 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006025 * @val: an XPath object
6026 *
6027 * Converts an XPath object to its boolean value
6028 *
6029 * Returns the boolean value
6030 */
6031int
6032xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6033 int ret = 0;
6034
6035 if (val == NULL)
6036 return(0);
6037 switch (val->type) {
6038 case XPATH_UNDEFINED:
6039#ifdef DEBUG_EXPR
6040 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6041#endif
6042 ret = 0;
6043 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006044 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00006045 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006046 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6047 break;
6048 case XPATH_STRING:
6049 ret = xmlXPathCastStringToBoolean(val->stringval);
6050 break;
6051 case XPATH_NUMBER:
6052 ret = xmlXPathCastNumberToBoolean(val->floatval);
6053 break;
6054 case XPATH_BOOLEAN:
6055 ret = val->boolval;
6056 break;
6057 case XPATH_USERS:
6058 case XPATH_POINT:
6059 case XPATH_RANGE:
6060 case XPATH_LOCATIONSET:
6061 TODO;
6062 ret = 0;
6063 break;
6064 }
6065 return(ret);
6066}
6067
6068
6069/**
6070 * xmlXPathConvertBoolean:
6071 * @val: an XPath object
6072 *
6073 * Converts an existing object to its boolean() equivalent
6074 *
6075 * Returns the new object, the old one is freed (or the operation
6076 * is done directly on @val)
6077 */
6078xmlXPathObjectPtr
6079xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6080 xmlXPathObjectPtr ret;
6081
6082 if (val == NULL)
6083 return(xmlXPathNewBoolean(0));
6084 if (val->type == XPATH_BOOLEAN)
6085 return(val);
6086 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6087 xmlXPathFreeObject(val);
6088 return(ret);
6089}
6090
Owen Taylor3473f882001-02-23 17:55:21 +00006091/************************************************************************
6092 * *
6093 * Routines to handle XPath contexts *
6094 * *
6095 ************************************************************************/
6096
6097/**
6098 * xmlXPathNewContext:
6099 * @doc: the XML document
6100 *
6101 * Create a new xmlXPathContext
6102 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006103 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006104 */
6105xmlXPathContextPtr
6106xmlXPathNewContext(xmlDocPtr doc) {
6107 xmlXPathContextPtr ret;
6108
6109 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6110 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006111 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006112 return(NULL);
6113 }
6114 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6115 ret->doc = doc;
6116 ret->node = NULL;
6117
6118 ret->varHash = NULL;
6119
6120 ret->nb_types = 0;
6121 ret->max_types = 0;
6122 ret->types = NULL;
6123
6124 ret->funcHash = xmlHashCreate(0);
6125
6126 ret->nb_axis = 0;
6127 ret->max_axis = 0;
6128 ret->axis = NULL;
6129
6130 ret->nsHash = NULL;
6131 ret->user = NULL;
6132
6133 ret->contextSize = -1;
6134 ret->proximityPosition = -1;
6135
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006136#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006137 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006138 xmlXPathFreeContext(ret);
6139 return(NULL);
6140 }
6141#endif
6142
Daniel Veillard45490ae2008-07-29 09:13:19 +00006143 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006144
Owen Taylor3473f882001-02-23 17:55:21 +00006145 return(ret);
6146}
6147
6148/**
6149 * xmlXPathFreeContext:
6150 * @ctxt: the context to free
6151 *
6152 * Free up an xmlXPathContext
6153 */
6154void
6155xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006156 if (ctxt == NULL) return;
6157
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006158 if (ctxt->cache != NULL)
6159 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006160 xmlXPathRegisteredNsCleanup(ctxt);
6161 xmlXPathRegisteredFuncsCleanup(ctxt);
6162 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006163 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006164 xmlFree(ctxt);
6165}
6166
6167/************************************************************************
6168 * *
6169 * Routines to handle XPath parser contexts *
6170 * *
6171 ************************************************************************/
6172
6173#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006174 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006175 __xmlRaiseError(NULL, NULL, NULL, \
6176 NULL, NULL, XML_FROM_XPATH, \
6177 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6178 __FILE__, __LINE__, \
6179 NULL, NULL, NULL, 0, 0, \
6180 "NULL context pointer\n"); \
6181 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006182 } \
6183
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006184#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006185 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006186 __xmlRaiseError(NULL, NULL, NULL, \
6187 NULL, NULL, XML_FROM_XPATH, \
6188 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6189 __FILE__, __LINE__, \
6190 NULL, NULL, NULL, 0, 0, \
6191 "NULL context pointer\n"); \
6192 return(-1); \
6193 } \
6194
Owen Taylor3473f882001-02-23 17:55:21 +00006195
6196#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006197 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006198 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006199 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006200 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006201 }
Owen Taylor3473f882001-02-23 17:55:21 +00006202
6203
6204/**
6205 * xmlXPathNewParserContext:
6206 * @str: the XPath expression
6207 * @ctxt: the XPath context
6208 *
6209 * Create a new xmlXPathParserContext
6210 *
6211 * Returns the xmlXPathParserContext just allocated.
6212 */
6213xmlXPathParserContextPtr
6214xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6215 xmlXPathParserContextPtr ret;
6216
6217 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6218 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006219 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006220 return(NULL);
6221 }
6222 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6223 ret->cur = ret->base = str;
6224 ret->context = ctxt;
6225
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006226 ret->comp = xmlXPathNewCompExpr();
6227 if (ret->comp == NULL) {
6228 xmlFree(ret->valueTab);
6229 xmlFree(ret);
6230 return(NULL);
6231 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006232 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6233 ret->comp->dict = ctxt->dict;
6234 xmlDictReference(ret->comp->dict);
6235 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006236
6237 return(ret);
6238}
6239
6240/**
6241 * xmlXPathCompParserContext:
6242 * @comp: the XPath compiled expression
6243 * @ctxt: the XPath context
6244 *
6245 * Create a new xmlXPathParserContext when processing a compiled expression
6246 *
6247 * Returns the xmlXPathParserContext just allocated.
6248 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006249static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006250xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6251 xmlXPathParserContextPtr ret;
6252
6253 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6254 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006255 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006256 return(NULL);
6257 }
6258 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6259
Owen Taylor3473f882001-02-23 17:55:21 +00006260 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006261 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006262 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006263 if (ret->valueTab == NULL) {
6264 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006265 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006266 return(NULL);
6267 }
Owen Taylor3473f882001-02-23 17:55:21 +00006268 ret->valueNr = 0;
6269 ret->valueMax = 10;
6270 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006271 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006272
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006273 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006274 ret->comp = comp;
6275
Owen Taylor3473f882001-02-23 17:55:21 +00006276 return(ret);
6277}
6278
6279/**
6280 * xmlXPathFreeParserContext:
6281 * @ctxt: the context to free
6282 *
6283 * Free up an xmlXPathParserContext
6284 */
6285void
6286xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6287 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006288 xmlFree(ctxt->valueTab);
6289 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006290 if (ctxt->comp != NULL) {
6291#ifdef XPATH_STREAMING
6292 if (ctxt->comp->stream != NULL) {
6293 xmlFreePatternList(ctxt->comp->stream);
6294 ctxt->comp->stream = NULL;
6295 }
6296#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006297 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006298 }
Owen Taylor3473f882001-02-23 17:55:21 +00006299 xmlFree(ctxt);
6300}
6301
6302/************************************************************************
6303 * *
6304 * The implicit core function library *
6305 * *
6306 ************************************************************************/
6307
Owen Taylor3473f882001-02-23 17:55:21 +00006308/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006309 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006310 * @node: a node pointer
6311 *
6312 * Function computing the beginning of the string value of the node,
6313 * used to speed up comparisons
6314 *
6315 * Returns an int usable as a hash
6316 */
6317static unsigned int
6318xmlXPathNodeValHash(xmlNodePtr node) {
6319 int len = 2;
6320 const xmlChar * string = NULL;
6321 xmlNodePtr tmp = NULL;
6322 unsigned int ret = 0;
6323
6324 if (node == NULL)
6325 return(0);
6326
Daniel Veillard9adc0462003-03-24 18:39:54 +00006327 if (node->type == XML_DOCUMENT_NODE) {
6328 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6329 if (tmp == NULL)
6330 node = node->children;
6331 else
6332 node = tmp;
6333
6334 if (node == NULL)
6335 return(0);
6336 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006337
6338 switch (node->type) {
6339 case XML_COMMENT_NODE:
6340 case XML_PI_NODE:
6341 case XML_CDATA_SECTION_NODE:
6342 case XML_TEXT_NODE:
6343 string = node->content;
6344 if (string == NULL)
6345 return(0);
6346 if (string[0] == 0)
6347 return(0);
6348 return(((unsigned int) string[0]) +
6349 (((unsigned int) string[1]) << 8));
6350 case XML_NAMESPACE_DECL:
6351 string = ((xmlNsPtr)node)->href;
6352 if (string == NULL)
6353 return(0);
6354 if (string[0] == 0)
6355 return(0);
6356 return(((unsigned int) string[0]) +
6357 (((unsigned int) string[1]) << 8));
6358 case XML_ATTRIBUTE_NODE:
6359 tmp = ((xmlAttrPtr) node)->children;
6360 break;
6361 case XML_ELEMENT_NODE:
6362 tmp = node->children;
6363 break;
6364 default:
6365 return(0);
6366 }
6367 while (tmp != NULL) {
6368 switch (tmp->type) {
6369 case XML_COMMENT_NODE:
6370 case XML_PI_NODE:
6371 case XML_CDATA_SECTION_NODE:
6372 case XML_TEXT_NODE:
6373 string = tmp->content;
6374 break;
6375 case XML_NAMESPACE_DECL:
6376 string = ((xmlNsPtr)tmp)->href;
6377 break;
6378 default:
6379 break;
6380 }
6381 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006382 if (len == 1) {
6383 return(ret + (((unsigned int) string[0]) << 8));
6384 }
6385 if (string[1] == 0) {
6386 len = 1;
6387 ret = (unsigned int) string[0];
6388 } else {
6389 return(((unsigned int) string[0]) +
6390 (((unsigned int) string[1]) << 8));
6391 }
6392 }
6393 /*
6394 * Skip to next node
6395 */
6396 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6397 if (tmp->children->type != XML_ENTITY_DECL) {
6398 tmp = tmp->children;
6399 continue;
6400 }
6401 }
6402 if (tmp == node)
6403 break;
6404
6405 if (tmp->next != NULL) {
6406 tmp = tmp->next;
6407 continue;
6408 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006409
Daniel Veillardf06307e2001-07-03 10:35:50 +00006410 do {
6411 tmp = tmp->parent;
6412 if (tmp == NULL)
6413 break;
6414 if (tmp == node) {
6415 tmp = NULL;
6416 break;
6417 }
6418 if (tmp->next != NULL) {
6419 tmp = tmp->next;
6420 break;
6421 }
6422 } while (tmp != NULL);
6423 }
6424 return(ret);
6425}
6426
6427/**
6428 * xmlXPathStringHash:
6429 * @string: a string
6430 *
6431 * Function computing the beginning of the string value of the node,
6432 * used to speed up comparisons
6433 *
6434 * Returns an int usable as a hash
6435 */
6436static unsigned int
6437xmlXPathStringHash(const xmlChar * string) {
6438 if (string == NULL)
6439 return((unsigned int) 0);
6440 if (string[0] == 0)
6441 return(0);
6442 return(((unsigned int) string[0]) +
6443 (((unsigned int) string[1]) << 8));
6444}
6445
6446/**
Owen Taylor3473f882001-02-23 17:55:21 +00006447 * xmlXPathCompareNodeSetFloat:
6448 * @ctxt: the XPath Parser context
6449 * @inf: less than (1) or greater than (0)
6450 * @strict: is the comparison strict
6451 * @arg: the node set
6452 * @f: the value
6453 *
6454 * Implement the compare operation between a nodeset and a number
6455 * @ns < @val (1, 1, ...
6456 * @ns <= @val (1, 0, ...
6457 * @ns > @val (0, 1, ...
6458 * @ns >= @val (0, 0, ...
6459 *
6460 * If one object to be compared is a node-set and the other is a number,
6461 * then the comparison will be true if and only if there is a node in the
6462 * node-set such that the result of performing the comparison on the number
6463 * to be compared and on the result of converting the string-value of that
6464 * node to a number using the number function is true.
6465 *
6466 * Returns 0 or 1 depending on the results of the test.
6467 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006468static int
Owen Taylor3473f882001-02-23 17:55:21 +00006469xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6470 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6471 int i, ret = 0;
6472 xmlNodeSetPtr ns;
6473 xmlChar *str2;
6474
6475 if ((f == NULL) || (arg == NULL) ||
6476 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006477 xmlXPathReleaseObject(ctxt->context, arg);
6478 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006479 return(0);
6480 }
6481 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006482 if (ns != NULL) {
6483 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006484 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006485 if (str2 != NULL) {
6486 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006487 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006488 xmlFree(str2);
6489 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006490 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006491 ret = xmlXPathCompareValues(ctxt, inf, strict);
6492 if (ret)
6493 break;
6494 }
6495 }
Owen Taylor3473f882001-02-23 17:55:21 +00006496 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006497 xmlXPathReleaseObject(ctxt->context, arg);
6498 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006499 return(ret);
6500}
6501
6502/**
6503 * xmlXPathCompareNodeSetString:
6504 * @ctxt: the XPath Parser context
6505 * @inf: less than (1) or greater than (0)
6506 * @strict: is the comparison strict
6507 * @arg: the node set
6508 * @s: the value
6509 *
6510 * Implement the compare operation between a nodeset and a string
6511 * @ns < @val (1, 1, ...
6512 * @ns <= @val (1, 0, ...
6513 * @ns > @val (0, 1, ...
6514 * @ns >= @val (0, 0, ...
6515 *
6516 * If one object to be compared is a node-set and the other is a string,
6517 * then the comparison will be true if and only if there is a node in
6518 * the node-set such that the result of performing the comparison on the
6519 * string-value of the node and the other string is true.
6520 *
6521 * Returns 0 or 1 depending on the results of the test.
6522 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006523static int
Owen Taylor3473f882001-02-23 17:55:21 +00006524xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6525 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6526 int i, ret = 0;
6527 xmlNodeSetPtr ns;
6528 xmlChar *str2;
6529
6530 if ((s == NULL) || (arg == NULL) ||
6531 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006532 xmlXPathReleaseObject(ctxt->context, arg);
6533 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006534 return(0);
6535 }
6536 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006537 if (ns != NULL) {
6538 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006539 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006540 if (str2 != NULL) {
6541 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006542 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006543 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006544 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006545 ret = xmlXPathCompareValues(ctxt, inf, strict);
6546 if (ret)
6547 break;
6548 }
6549 }
Owen Taylor3473f882001-02-23 17:55:21 +00006550 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006551 xmlXPathReleaseObject(ctxt->context, arg);
6552 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006553 return(ret);
6554}
6555
6556/**
6557 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006558 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006559 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006560 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006561 * @arg2: the second node set object
6562 *
6563 * Implement the compare operation on nodesets:
6564 *
6565 * If both objects to be compared are node-sets, then the comparison
6566 * will be true if and only if there is a node in the first node-set
6567 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006568 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006569 * ....
6570 * When neither object to be compared is a node-set and the operator
6571 * is <=, <, >= or >, then the objects are compared by converting both
6572 * objects to numbers and comparing the numbers according to IEEE 754.
6573 * ....
6574 * The number function converts its argument to a number as follows:
6575 * - a string that consists of optional whitespace followed by an
6576 * optional minus sign followed by a Number followed by whitespace
6577 * is converted to the IEEE 754 number that is nearest (according
6578 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6579 * represented by the string; any other string is converted to NaN
6580 *
6581 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006582 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006583 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006584static int
6585xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006586 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6587 int i, j, init = 0;
6588 double val1;
6589 double *values2;
6590 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006591 xmlNodeSetPtr ns1;
6592 xmlNodeSetPtr ns2;
6593
6594 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006595 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6596 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006597 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006598 }
Owen Taylor3473f882001-02-23 17:55:21 +00006599 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006600 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6601 xmlXPathFreeObject(arg1);
6602 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006603 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006604 }
Owen Taylor3473f882001-02-23 17:55:21 +00006605
6606 ns1 = arg1->nodesetval;
6607 ns2 = arg2->nodesetval;
6608
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006609 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006610 xmlXPathFreeObject(arg1);
6611 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006612 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006613 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006614 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006615 xmlXPathFreeObject(arg1);
6616 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006617 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006618 }
Owen Taylor3473f882001-02-23 17:55:21 +00006619
6620 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6621 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006622 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006623 xmlXPathFreeObject(arg1);
6624 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006625 return(0);
6626 }
6627 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006628 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006629 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006630 continue;
6631 for (j = 0;j < ns2->nodeNr;j++) {
6632 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006633 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006634 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006635 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006636 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006637 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006638 ret = (val1 < values2[j]);
6639 else if (inf && !strict)
6640 ret = (val1 <= values2[j]);
6641 else if (!inf && strict)
6642 ret = (val1 > values2[j]);
6643 else if (!inf && !strict)
6644 ret = (val1 >= values2[j]);
6645 if (ret)
6646 break;
6647 }
6648 if (ret)
6649 break;
6650 init = 1;
6651 }
6652 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006653 xmlXPathFreeObject(arg1);
6654 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006655 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006656}
6657
6658/**
6659 * xmlXPathCompareNodeSetValue:
6660 * @ctxt: the XPath Parser context
6661 * @inf: less than (1) or greater than (0)
6662 * @strict: is the comparison strict
6663 * @arg: the node set
6664 * @val: the value
6665 *
6666 * Implement the compare operation between a nodeset and a value
6667 * @ns < @val (1, 1, ...
6668 * @ns <= @val (1, 0, ...
6669 * @ns > @val (0, 1, ...
6670 * @ns >= @val (0, 0, ...
6671 *
6672 * If one object to be compared is a node-set and the other is a boolean,
6673 * then the comparison will be true if and only if the result of performing
6674 * the comparison on the boolean and on the result of converting
6675 * the node-set to a boolean using the boolean function is true.
6676 *
6677 * Returns 0 or 1 depending on the results of the test.
6678 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006679static int
Owen Taylor3473f882001-02-23 17:55:21 +00006680xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6681 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6682 if ((val == NULL) || (arg == NULL) ||
6683 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6684 return(0);
6685
6686 switch(val->type) {
6687 case XPATH_NUMBER:
6688 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6689 case XPATH_NODESET:
6690 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006691 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006692 case XPATH_STRING:
6693 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6694 case XPATH_BOOLEAN:
6695 valuePush(ctxt, arg);
6696 xmlXPathBooleanFunction(ctxt, 1);
6697 valuePush(ctxt, val);
6698 return(xmlXPathCompareValues(ctxt, inf, strict));
6699 default:
6700 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006701 }
6702 return(0);
6703}
6704
6705/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006706 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006707 * @arg: the nodeset object argument
6708 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006709 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006710 *
6711 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6712 * If one object to be compared is a node-set and the other is a string,
6713 * then the comparison will be true if and only if there is a node in
6714 * the node-set such that the result of performing the comparison on the
6715 * string-value of the node and the other string is true.
6716 *
6717 * Returns 0 or 1 depending on the results of the test.
6718 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006719static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006720xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006721{
Owen Taylor3473f882001-02-23 17:55:21 +00006722 int i;
6723 xmlNodeSetPtr ns;
6724 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006725 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006726
6727 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006728 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6729 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006730 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006731 /*
6732 * A NULL nodeset compared with a string is always false
6733 * (since there is no node equal, and no node not equal)
6734 */
6735 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006736 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006737 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006738 for (i = 0; i < ns->nodeNr; i++) {
6739 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6740 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6741 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6742 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006743 if (neq)
6744 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006745 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006746 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6747 if (neq)
6748 continue;
6749 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006750 } else if (neq) {
6751 if (str2 != NULL)
6752 xmlFree(str2);
6753 return (1);
6754 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006755 if (str2 != NULL)
6756 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006757 } else if (neq)
6758 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006759 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006760 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006761}
6762
6763/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006764 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006765 * @arg: the nodeset object argument
6766 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006767 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006768 *
6769 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6770 * If one object to be compared is a node-set and the other is a number,
6771 * then the comparison will be true if and only if there is a node in
6772 * the node-set such that the result of performing the comparison on the
6773 * number to be compared and on the result of converting the string-value
6774 * of that node to a number using the number function is true.
6775 *
6776 * Returns 0 or 1 depending on the results of the test.
6777 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006778static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006779xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6780 xmlXPathObjectPtr arg, double f, int neq) {
6781 int i, ret=0;
6782 xmlNodeSetPtr ns;
6783 xmlChar *str2;
6784 xmlXPathObjectPtr val;
6785 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006786
6787 if ((arg == NULL) ||
6788 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6789 return(0);
6790
William M. Brack0c022ad2002-07-12 00:56:01 +00006791 ns = arg->nodesetval;
6792 if (ns != NULL) {
6793 for (i=0;i<ns->nodeNr;i++) {
6794 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6795 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006796 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006797 xmlFree(str2);
6798 xmlXPathNumberFunction(ctxt, 1);
6799 val = valuePop(ctxt);
6800 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006801 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006802 if (!xmlXPathIsNaN(v)) {
6803 if ((!neq) && (v==f)) {
6804 ret = 1;
6805 break;
6806 } else if ((neq) && (v!=f)) {
6807 ret = 1;
6808 break;
6809 }
William M. Brack32f0f712005-07-14 07:00:33 +00006810 } else { /* NaN is unequal to any value */
6811 if (neq)
6812 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006813 }
6814 }
6815 }
6816 }
6817
6818 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006819}
6820
6821
6822/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006823 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006824 * @arg1: first nodeset object argument
6825 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006826 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006827 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006828 * Implement the equal / not equal operation on XPath nodesets:
6829 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006830 * If both objects to be compared are node-sets, then the comparison
6831 * will be true if and only if there is a node in the first node-set and
6832 * a node in the second node-set such that the result of performing the
6833 * comparison on the string-values of the two nodes is true.
6834 *
6835 * (needless to say, this is a costly operation)
6836 *
6837 * Returns 0 or 1 depending on the results of the test.
6838 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006839static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006840xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006841 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006842 unsigned int *hashs1;
6843 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006844 xmlChar **values1;
6845 xmlChar **values2;
6846 int ret = 0;
6847 xmlNodeSetPtr ns1;
6848 xmlNodeSetPtr ns2;
6849
6850 if ((arg1 == NULL) ||
6851 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6852 return(0);
6853 if ((arg2 == NULL) ||
6854 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6855 return(0);
6856
6857 ns1 = arg1->nodesetval;
6858 ns2 = arg2->nodesetval;
6859
Daniel Veillard911f49a2001-04-07 15:39:35 +00006860 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006861 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006862 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006863 return(0);
6864
6865 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006866 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006867 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006868 if (neq == 0)
6869 for (i = 0;i < ns1->nodeNr;i++)
6870 for (j = 0;j < ns2->nodeNr;j++)
6871 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6872 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006873
6874 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006875 if (values1 == NULL) {
6876 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006877 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006878 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006879 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6880 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006881 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006882 xmlFree(values1);
6883 return(0);
6884 }
Owen Taylor3473f882001-02-23 17:55:21 +00006885 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6886 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6887 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006888 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006889 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006890 xmlFree(values1);
6891 return(0);
6892 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006893 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6894 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006895 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006896 xmlFree(hashs1);
6897 xmlFree(values1);
6898 xmlFree(values2);
6899 return(0);
6900 }
Owen Taylor3473f882001-02-23 17:55:21 +00006901 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6902 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006903 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006904 for (j = 0;j < ns2->nodeNr;j++) {
6905 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006906 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006907 if (hashs1[i] != hashs2[j]) {
6908 if (neq) {
6909 ret = 1;
6910 break;
6911 }
6912 }
6913 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006914 if (values1[i] == NULL)
6915 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6916 if (values2[j] == NULL)
6917 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006918 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006919 if (ret)
6920 break;
6921 }
Owen Taylor3473f882001-02-23 17:55:21 +00006922 }
6923 if (ret)
6924 break;
6925 }
6926 for (i = 0;i < ns1->nodeNr;i++)
6927 if (values1[i] != NULL)
6928 xmlFree(values1[i]);
6929 for (j = 0;j < ns2->nodeNr;j++)
6930 if (values2[j] != NULL)
6931 xmlFree(values2[j]);
6932 xmlFree(values1);
6933 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006934 xmlFree(hashs1);
6935 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006936 return(ret);
6937}
6938
William M. Brack0c022ad2002-07-12 00:56:01 +00006939static int
6940xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6941 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006942 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006943 /*
6944 *At this point we are assured neither arg1 nor arg2
6945 *is a nodeset, so we can just pick the appropriate routine.
6946 */
Owen Taylor3473f882001-02-23 17:55:21 +00006947 switch (arg1->type) {
6948 case XPATH_UNDEFINED:
6949#ifdef DEBUG_EXPR
6950 xmlGenericError(xmlGenericErrorContext,
6951 "Equal: undefined\n");
6952#endif
6953 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006954 case XPATH_BOOLEAN:
6955 switch (arg2->type) {
6956 case XPATH_UNDEFINED:
6957#ifdef DEBUG_EXPR
6958 xmlGenericError(xmlGenericErrorContext,
6959 "Equal: undefined\n");
6960#endif
6961 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006962 case XPATH_BOOLEAN:
6963#ifdef DEBUG_EXPR
6964 xmlGenericError(xmlGenericErrorContext,
6965 "Equal: %d boolean %d \n",
6966 arg1->boolval, arg2->boolval);
6967#endif
6968 ret = (arg1->boolval == arg2->boolval);
6969 break;
6970 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006971 ret = (arg1->boolval ==
6972 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006973 break;
6974 case XPATH_STRING:
6975 if ((arg2->stringval == NULL) ||
6976 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006977 else
Owen Taylor3473f882001-02-23 17:55:21 +00006978 ret = 1;
6979 ret = (arg1->boolval == ret);
6980 break;
6981 case XPATH_USERS:
6982 case XPATH_POINT:
6983 case XPATH_RANGE:
6984 case XPATH_LOCATIONSET:
6985 TODO
6986 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006987 case XPATH_NODESET:
6988 case XPATH_XSLT_TREE:
6989 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006990 }
6991 break;
6992 case XPATH_NUMBER:
6993 switch (arg2->type) {
6994 case XPATH_UNDEFINED:
6995#ifdef DEBUG_EXPR
6996 xmlGenericError(xmlGenericErrorContext,
6997 "Equal: undefined\n");
6998#endif
6999 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007000 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00007001 ret = (arg2->boolval==
7002 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00007003 break;
7004 case XPATH_STRING:
7005 valuePush(ctxt, arg2);
7006 xmlXPathNumberFunction(ctxt, 1);
7007 arg2 = valuePop(ctxt);
7008 /* no break on purpose */
7009 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007010 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007011 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007012 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007013 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007014 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7015 if (xmlXPathIsInf(arg2->floatval) == 1)
7016 ret = 1;
7017 else
7018 ret = 0;
7019 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7020 if (xmlXPathIsInf(arg2->floatval) == -1)
7021 ret = 1;
7022 else
7023 ret = 0;
7024 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7025 if (xmlXPathIsInf(arg1->floatval) == 1)
7026 ret = 1;
7027 else
7028 ret = 0;
7029 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7030 if (xmlXPathIsInf(arg1->floatval) == -1)
7031 ret = 1;
7032 else
7033 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007034 } else {
7035 ret = (arg1->floatval == arg2->floatval);
7036 }
Owen Taylor3473f882001-02-23 17:55:21 +00007037 break;
7038 case XPATH_USERS:
7039 case XPATH_POINT:
7040 case XPATH_RANGE:
7041 case XPATH_LOCATIONSET:
7042 TODO
7043 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007044 case XPATH_NODESET:
7045 case XPATH_XSLT_TREE:
7046 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007047 }
7048 break;
7049 case XPATH_STRING:
7050 switch (arg2->type) {
7051 case XPATH_UNDEFINED:
7052#ifdef DEBUG_EXPR
7053 xmlGenericError(xmlGenericErrorContext,
7054 "Equal: undefined\n");
7055#endif
7056 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007057 case XPATH_BOOLEAN:
7058 if ((arg1->stringval == NULL) ||
7059 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007060 else
Owen Taylor3473f882001-02-23 17:55:21 +00007061 ret = 1;
7062 ret = (arg2->boolval == ret);
7063 break;
7064 case XPATH_STRING:
7065 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7066 break;
7067 case XPATH_NUMBER:
7068 valuePush(ctxt, arg1);
7069 xmlXPathNumberFunction(ctxt, 1);
7070 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007071 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007072 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007073 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007074 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007075 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7076 if (xmlXPathIsInf(arg2->floatval) == 1)
7077 ret = 1;
7078 else
7079 ret = 0;
7080 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7081 if (xmlXPathIsInf(arg2->floatval) == -1)
7082 ret = 1;
7083 else
7084 ret = 0;
7085 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7086 if (xmlXPathIsInf(arg1->floatval) == 1)
7087 ret = 1;
7088 else
7089 ret = 0;
7090 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7091 if (xmlXPathIsInf(arg1->floatval) == -1)
7092 ret = 1;
7093 else
7094 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007095 } else {
7096 ret = (arg1->floatval == arg2->floatval);
7097 }
Owen Taylor3473f882001-02-23 17:55:21 +00007098 break;
7099 case XPATH_USERS:
7100 case XPATH_POINT:
7101 case XPATH_RANGE:
7102 case XPATH_LOCATIONSET:
7103 TODO
7104 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007105 case XPATH_NODESET:
7106 case XPATH_XSLT_TREE:
7107 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007108 }
7109 break;
7110 case XPATH_USERS:
7111 case XPATH_POINT:
7112 case XPATH_RANGE:
7113 case XPATH_LOCATIONSET:
7114 TODO
7115 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007116 case XPATH_NODESET:
7117 case XPATH_XSLT_TREE:
7118 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007119 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007120 xmlXPathReleaseObject(ctxt->context, arg1);
7121 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007122 return(ret);
7123}
7124
William M. Brack0c022ad2002-07-12 00:56:01 +00007125/**
7126 * xmlXPathEqualValues:
7127 * @ctxt: the XPath Parser context
7128 *
7129 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7130 *
7131 * Returns 0 or 1 depending on the results of the test.
7132 */
7133int
7134xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7135 xmlXPathObjectPtr arg1, arg2, argtmp;
7136 int ret = 0;
7137
Daniel Veillard6128c012004-11-08 17:16:15 +00007138 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007139 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007140 arg1 = valuePop(ctxt);
7141 if ((arg1 == NULL) || (arg2 == NULL)) {
7142 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007143 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007144 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007145 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007146 XP_ERROR0(XPATH_INVALID_OPERAND);
7147 }
7148
7149 if (arg1 == arg2) {
7150#ifdef DEBUG_EXPR
7151 xmlGenericError(xmlGenericErrorContext,
7152 "Equal: by pointer\n");
7153#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007154 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007155 return(1);
7156 }
7157
7158 /*
7159 *If either argument is a nodeset, it's a 'special case'
7160 */
7161 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7162 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7163 /*
7164 *Hack it to assure arg1 is the nodeset
7165 */
7166 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7167 argtmp = arg2;
7168 arg2 = arg1;
7169 arg1 = argtmp;
7170 }
7171 switch (arg2->type) {
7172 case XPATH_UNDEFINED:
7173#ifdef DEBUG_EXPR
7174 xmlGenericError(xmlGenericErrorContext,
7175 "Equal: undefined\n");
7176#endif
7177 break;
7178 case XPATH_NODESET:
7179 case XPATH_XSLT_TREE:
7180 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7181 break;
7182 case XPATH_BOOLEAN:
7183 if ((arg1->nodesetval == NULL) ||
7184 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007185 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007186 ret = 1;
7187 ret = (ret == arg2->boolval);
7188 break;
7189 case XPATH_NUMBER:
7190 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7191 break;
7192 case XPATH_STRING:
7193 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7194 break;
7195 case XPATH_USERS:
7196 case XPATH_POINT:
7197 case XPATH_RANGE:
7198 case XPATH_LOCATIONSET:
7199 TODO
7200 break;
7201 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007202 xmlXPathReleaseObject(ctxt->context, arg1);
7203 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007204 return(ret);
7205 }
7206
7207 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7208}
7209
7210/**
7211 * xmlXPathNotEqualValues:
7212 * @ctxt: the XPath Parser context
7213 *
7214 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7215 *
7216 * Returns 0 or 1 depending on the results of the test.
7217 */
7218int
7219xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7220 xmlXPathObjectPtr arg1, arg2, argtmp;
7221 int ret = 0;
7222
Daniel Veillard6128c012004-11-08 17:16:15 +00007223 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007224 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007225 arg1 = valuePop(ctxt);
7226 if ((arg1 == NULL) || (arg2 == NULL)) {
7227 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007228 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007229 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007230 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007231 XP_ERROR0(XPATH_INVALID_OPERAND);
7232 }
7233
7234 if (arg1 == arg2) {
7235#ifdef DEBUG_EXPR
7236 xmlGenericError(xmlGenericErrorContext,
7237 "NotEqual: by pointer\n");
7238#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007239 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007240 return(0);
7241 }
7242
7243 /*
7244 *If either argument is a nodeset, it's a 'special case'
7245 */
7246 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7247 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7248 /*
7249 *Hack it to assure arg1 is the nodeset
7250 */
7251 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7252 argtmp = arg2;
7253 arg2 = arg1;
7254 arg1 = argtmp;
7255 }
7256 switch (arg2->type) {
7257 case XPATH_UNDEFINED:
7258#ifdef DEBUG_EXPR
7259 xmlGenericError(xmlGenericErrorContext,
7260 "NotEqual: undefined\n");
7261#endif
7262 break;
7263 case XPATH_NODESET:
7264 case XPATH_XSLT_TREE:
7265 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7266 break;
7267 case XPATH_BOOLEAN:
7268 if ((arg1->nodesetval == NULL) ||
7269 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007270 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007271 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007272 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007273 break;
7274 case XPATH_NUMBER:
7275 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7276 break;
7277 case XPATH_STRING:
7278 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7279 break;
7280 case XPATH_USERS:
7281 case XPATH_POINT:
7282 case XPATH_RANGE:
7283 case XPATH_LOCATIONSET:
7284 TODO
7285 break;
7286 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007287 xmlXPathReleaseObject(ctxt->context, arg1);
7288 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007289 return(ret);
7290 }
7291
7292 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7293}
Owen Taylor3473f882001-02-23 17:55:21 +00007294
7295/**
7296 * xmlXPathCompareValues:
7297 * @ctxt: the XPath Parser context
7298 * @inf: less than (1) or greater than (0)
7299 * @strict: is the comparison strict
7300 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007301 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007302 * @arg1 < @arg2 (1, 1, ...
7303 * @arg1 <= @arg2 (1, 0, ...
7304 * @arg1 > @arg2 (0, 1, ...
7305 * @arg1 >= @arg2 (0, 0, ...
7306 *
7307 * When neither object to be compared is a node-set and the operator is
7308 * <=, <, >=, >, then the objects are compared by converted both objects
7309 * to numbers and comparing the numbers according to IEEE 754. The <
7310 * comparison will be true if and only if the first number is less than the
7311 * second number. The <= comparison will be true if and only if the first
7312 * number is less than or equal to the second number. The > comparison
7313 * will be true if and only if the first number is greater than the second
7314 * number. The >= comparison will be true if and only if the first number
7315 * is greater than or equal to the second number.
7316 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007317 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007318 */
7319int
7320xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007321 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007322 xmlXPathObjectPtr arg1, arg2;
7323
Daniel Veillard6128c012004-11-08 17:16:15 +00007324 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007325 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007326 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007327 if ((arg1 == NULL) || (arg2 == NULL)) {
7328 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007329 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007330 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007331 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007332 XP_ERROR0(XPATH_INVALID_OPERAND);
7333 }
7334
William M. Brack0c022ad2002-07-12 00:56:01 +00007335 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7336 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007337 /*
7338 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7339 * are not freed from within this routine; they will be freed from the
7340 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7341 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007342 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7343 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007344 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007345 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007346 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007347 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7348 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007349 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007350 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7351 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007352 }
7353 }
7354 return(ret);
7355 }
7356
7357 if (arg1->type != XPATH_NUMBER) {
7358 valuePush(ctxt, arg1);
7359 xmlXPathNumberFunction(ctxt, 1);
7360 arg1 = valuePop(ctxt);
7361 }
7362 if (arg1->type != XPATH_NUMBER) {
7363 xmlXPathFreeObject(arg1);
7364 xmlXPathFreeObject(arg2);
7365 XP_ERROR0(XPATH_INVALID_OPERAND);
7366 }
7367 if (arg2->type != XPATH_NUMBER) {
7368 valuePush(ctxt, arg2);
7369 xmlXPathNumberFunction(ctxt, 1);
7370 arg2 = valuePop(ctxt);
7371 }
7372 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007373 xmlXPathReleaseObject(ctxt->context, arg1);
7374 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007375 XP_ERROR0(XPATH_INVALID_OPERAND);
7376 }
7377 /*
7378 * Add tests for infinity and nan
7379 * => feedback on 3.4 for Inf and NaN
7380 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007381 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007382 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007383 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007384 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007385 arg1i=xmlXPathIsInf(arg1->floatval);
7386 arg2i=xmlXPathIsInf(arg2->floatval);
7387 if (inf && strict) {
7388 if ((arg1i == -1 && arg2i != -1) ||
7389 (arg2i == 1 && arg1i != 1)) {
7390 ret = 1;
7391 } else if (arg1i == 0 && arg2i == 0) {
7392 ret = (arg1->floatval < arg2->floatval);
7393 } else {
7394 ret = 0;
7395 }
7396 }
7397 else if (inf && !strict) {
7398 if (arg1i == -1 || arg2i == 1) {
7399 ret = 1;
7400 } else if (arg1i == 0 && arg2i == 0) {
7401 ret = (arg1->floatval <= arg2->floatval);
7402 } else {
7403 ret = 0;
7404 }
7405 }
7406 else if (!inf && strict) {
7407 if ((arg1i == 1 && arg2i != 1) ||
7408 (arg2i == -1 && arg1i != -1)) {
7409 ret = 1;
7410 } else if (arg1i == 0 && arg2i == 0) {
7411 ret = (arg1->floatval > arg2->floatval);
7412 } else {
7413 ret = 0;
7414 }
7415 }
7416 else if (!inf && !strict) {
7417 if (arg1i == 1 || arg2i == -1) {
7418 ret = 1;
7419 } else if (arg1i == 0 && arg2i == 0) {
7420 ret = (arg1->floatval >= arg2->floatval);
7421 } else {
7422 ret = 0;
7423 }
7424 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007425 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007426 xmlXPathReleaseObject(ctxt->context, arg1);
7427 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007428 return(ret);
7429}
7430
7431/**
7432 * xmlXPathValueFlipSign:
7433 * @ctxt: the XPath Parser context
7434 *
7435 * Implement the unary - operation on an XPath object
7436 * The numeric operators convert their operands to numbers as if
7437 * by calling the number function.
7438 */
7439void
7440xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007441 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007442 CAST_TO_NUMBER;
7443 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007444 if (xmlXPathIsNaN(ctxt->value->floatval))
7445 ctxt->value->floatval=xmlXPathNAN;
7446 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7447 ctxt->value->floatval=xmlXPathNINF;
7448 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7449 ctxt->value->floatval=xmlXPathPINF;
7450 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007451 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7452 ctxt->value->floatval = xmlXPathNZERO;
7453 else
7454 ctxt->value->floatval = 0;
7455 }
7456 else
7457 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007458}
7459
7460/**
7461 * xmlXPathAddValues:
7462 * @ctxt: the XPath Parser context
7463 *
7464 * Implement the add operation on XPath objects:
7465 * The numeric operators convert their operands to numbers as if
7466 * by calling the number function.
7467 */
7468void
7469xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7470 xmlXPathObjectPtr arg;
7471 double val;
7472
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007473 arg = valuePop(ctxt);
7474 if (arg == NULL)
7475 XP_ERROR(XPATH_INVALID_OPERAND);
7476 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007477 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007478 CAST_TO_NUMBER;
7479 CHECK_TYPE(XPATH_NUMBER);
7480 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007481}
7482
7483/**
7484 * xmlXPathSubValues:
7485 * @ctxt: the XPath Parser context
7486 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007487 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007488 * The numeric operators convert their operands to numbers as if
7489 * by calling the number function.
7490 */
7491void
7492xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7493 xmlXPathObjectPtr arg;
7494 double val;
7495
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007496 arg = valuePop(ctxt);
7497 if (arg == NULL)
7498 XP_ERROR(XPATH_INVALID_OPERAND);
7499 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007500 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007501 CAST_TO_NUMBER;
7502 CHECK_TYPE(XPATH_NUMBER);
7503 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007504}
7505
7506/**
7507 * xmlXPathMultValues:
7508 * @ctxt: the XPath Parser context
7509 *
7510 * Implement the multiply operation on XPath objects:
7511 * The numeric operators convert their operands to numbers as if
7512 * by calling the number function.
7513 */
7514void
7515xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7516 xmlXPathObjectPtr arg;
7517 double val;
7518
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007519 arg = valuePop(ctxt);
7520 if (arg == NULL)
7521 XP_ERROR(XPATH_INVALID_OPERAND);
7522 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007523 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007524 CAST_TO_NUMBER;
7525 CHECK_TYPE(XPATH_NUMBER);
7526 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007527}
7528
7529/**
7530 * xmlXPathDivValues:
7531 * @ctxt: the XPath Parser context
7532 *
7533 * Implement the div operation on XPath objects @arg1 / @arg2:
7534 * The numeric operators convert their operands to numbers as if
7535 * by calling the number function.
7536 */
7537void
7538xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7539 xmlXPathObjectPtr arg;
7540 double val;
7541
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007542 arg = valuePop(ctxt);
7543 if (arg == NULL)
7544 XP_ERROR(XPATH_INVALID_OPERAND);
7545 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007546 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007547 CAST_TO_NUMBER;
7548 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007549 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7550 ctxt->value->floatval = xmlXPathNAN;
7551 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007552 if (ctxt->value->floatval == 0)
7553 ctxt->value->floatval = xmlXPathNAN;
7554 else if (ctxt->value->floatval > 0)
7555 ctxt->value->floatval = xmlXPathNINF;
7556 else if (ctxt->value->floatval < 0)
7557 ctxt->value->floatval = xmlXPathPINF;
7558 }
7559 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007560 if (ctxt->value->floatval == 0)
7561 ctxt->value->floatval = xmlXPathNAN;
7562 else if (ctxt->value->floatval > 0)
7563 ctxt->value->floatval = xmlXPathPINF;
7564 else if (ctxt->value->floatval < 0)
7565 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007566 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007567 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007568}
7569
7570/**
7571 * xmlXPathModValues:
7572 * @ctxt: the XPath Parser context
7573 *
7574 * Implement the mod operation on XPath objects: @arg1 / @arg2
7575 * The numeric operators convert their operands to numbers as if
7576 * by calling the number function.
7577 */
7578void
7579xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7580 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007581 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007582
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007583 arg = valuePop(ctxt);
7584 if (arg == NULL)
7585 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007586 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007587 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007588 CAST_TO_NUMBER;
7589 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007590 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007591 if (arg2 == 0)
7592 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007593 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007594 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007595 }
Owen Taylor3473f882001-02-23 17:55:21 +00007596}
7597
7598/************************************************************************
7599 * *
7600 * The traversal functions *
7601 * *
7602 ************************************************************************/
7603
Owen Taylor3473f882001-02-23 17:55:21 +00007604/*
7605 * A traversal function enumerates nodes along an axis.
7606 * Initially it must be called with NULL, and it indicates
7607 * termination on the axis by returning NULL.
7608 */
7609typedef xmlNodePtr (*xmlXPathTraversalFunction)
7610 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7611
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007612/*
7613 * xmlXPathTraversalFunctionExt:
7614 * A traversal function enumerates nodes along an axis.
7615 * Initially it must be called with NULL, and it indicates
7616 * termination on the axis by returning NULL.
7617 * The context node of the traversal is specified via @contextNode.
7618 */
7619typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7620 (xmlNodePtr cur, xmlNodePtr contextNode);
7621
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007622/*
7623 * xmlXPathNodeSetMergeFunction:
7624 * Used for merging node sets in xmlXPathCollectAndTest().
7625 */
7626typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7627 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7628
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007629
Owen Taylor3473f882001-02-23 17:55:21 +00007630/**
7631 * xmlXPathNextSelf:
7632 * @ctxt: the XPath Parser context
7633 * @cur: the current node in the traversal
7634 *
7635 * Traversal function for the "self" direction
7636 * The self axis contains just the context node itself
7637 *
7638 * Returns the next element following that axis
7639 */
7640xmlNodePtr
7641xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007642 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007643 if (cur == NULL)
7644 return(ctxt->context->node);
7645 return(NULL);
7646}
7647
7648/**
7649 * xmlXPathNextChild:
7650 * @ctxt: the XPath Parser context
7651 * @cur: the current node in the traversal
7652 *
7653 * Traversal function for the "child" direction
7654 * The child axis contains the children of the context node in document order.
7655 *
7656 * Returns the next element following that axis
7657 */
7658xmlNodePtr
7659xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007660 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007661 if (cur == NULL) {
7662 if (ctxt->context->node == NULL) return(NULL);
7663 switch (ctxt->context->node->type) {
7664 case XML_ELEMENT_NODE:
7665 case XML_TEXT_NODE:
7666 case XML_CDATA_SECTION_NODE:
7667 case XML_ENTITY_REF_NODE:
7668 case XML_ENTITY_NODE:
7669 case XML_PI_NODE:
7670 case XML_COMMENT_NODE:
7671 case XML_NOTATION_NODE:
7672 case XML_DTD_NODE:
7673 return(ctxt->context->node->children);
7674 case XML_DOCUMENT_NODE:
7675 case XML_DOCUMENT_TYPE_NODE:
7676 case XML_DOCUMENT_FRAG_NODE:
7677 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007678#ifdef LIBXML_DOCB_ENABLED
7679 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007680#endif
7681 return(((xmlDocPtr) ctxt->context->node)->children);
7682 case XML_ELEMENT_DECL:
7683 case XML_ATTRIBUTE_DECL:
7684 case XML_ENTITY_DECL:
7685 case XML_ATTRIBUTE_NODE:
7686 case XML_NAMESPACE_DECL:
7687 case XML_XINCLUDE_START:
7688 case XML_XINCLUDE_END:
7689 return(NULL);
7690 }
7691 return(NULL);
7692 }
7693 if ((cur->type == XML_DOCUMENT_NODE) ||
7694 (cur->type == XML_HTML_DOCUMENT_NODE))
7695 return(NULL);
7696 return(cur->next);
7697}
7698
7699/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007700 * xmlXPathNextChildElement:
7701 * @ctxt: the XPath Parser context
7702 * @cur: the current node in the traversal
7703 *
7704 * Traversal function for the "child" direction and nodes of type element.
7705 * The child axis contains the children of the context node in document order.
7706 *
7707 * Returns the next element following that axis
7708 */
7709static xmlNodePtr
7710xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7711 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7712 if (cur == NULL) {
7713 cur = ctxt->context->node;
7714 if (cur == NULL) return(NULL);
7715 /*
7716 * Get the first element child.
7717 */
7718 switch (cur->type) {
7719 case XML_ELEMENT_NODE:
7720 case XML_DOCUMENT_FRAG_NODE:
7721 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7722 case XML_ENTITY_NODE:
7723 cur = cur->children;
7724 if (cur != NULL) {
7725 if (cur->type == XML_ELEMENT_NODE)
7726 return(cur);
7727 do {
7728 cur = cur->next;
7729 } while ((cur != NULL) &&
7730 (cur->type != XML_ELEMENT_NODE));
7731 return(cur);
7732 }
7733 return(NULL);
7734 case XML_DOCUMENT_NODE:
7735 case XML_HTML_DOCUMENT_NODE:
7736#ifdef LIBXML_DOCB_ENABLED
7737 case XML_DOCB_DOCUMENT_NODE:
7738#endif
7739 return(xmlDocGetRootElement((xmlDocPtr) cur));
7740 default:
7741 return(NULL);
7742 }
7743 return(NULL);
7744 }
7745 /*
7746 * Get the next sibling element node.
7747 */
7748 switch (cur->type) {
7749 case XML_ELEMENT_NODE:
7750 case XML_TEXT_NODE:
7751 case XML_ENTITY_REF_NODE:
7752 case XML_ENTITY_NODE:
7753 case XML_CDATA_SECTION_NODE:
7754 case XML_PI_NODE:
7755 case XML_COMMENT_NODE:
7756 case XML_XINCLUDE_END:
7757 break;
7758 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7759 default:
7760 return(NULL);
7761 }
7762 if (cur->next != NULL) {
7763 if (cur->next->type == XML_ELEMENT_NODE)
7764 return(cur->next);
7765 cur = cur->next;
7766 do {
7767 cur = cur->next;
7768 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7769 return(cur);
7770 }
7771 return(NULL);
7772}
7773
7774/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007775 * xmlXPathNextDescendantOrSelfElemParent:
7776 * @ctxt: the XPath Parser context
7777 * @cur: the current node in the traversal
7778 *
7779 * Traversal function for the "descendant-or-self" axis.
7780 * Additionally it returns only nodes which can be parents of
7781 * element nodes.
7782 *
7783 *
7784 * Returns the next element following that axis
7785 */
7786static xmlNodePtr
7787xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7788 xmlNodePtr contextNode)
7789{
7790 if (cur == NULL) {
7791 if (contextNode == NULL)
7792 return(NULL);
7793 switch (contextNode->type) {
7794 case XML_ELEMENT_NODE:
7795 case XML_XINCLUDE_START:
7796 case XML_DOCUMENT_FRAG_NODE:
7797 case XML_DOCUMENT_NODE:
7798#ifdef LIBXML_DOCB_ENABLED
7799 case XML_DOCB_DOCUMENT_NODE:
7800#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007801 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007802 return(contextNode);
7803 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007804 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007805 }
7806 return(NULL);
7807 } else {
7808 xmlNodePtr start = cur;
7809
7810 while (cur != NULL) {
7811 switch (cur->type) {
7812 case XML_ELEMENT_NODE:
7813 /* TODO: OK to have XInclude here? */
7814 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007815 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007816 if (cur != start)
7817 return(cur);
7818 if (cur->children != NULL) {
7819 cur = cur->children;
7820 continue;
7821 }
7822 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007823 /* Not sure if we need those here. */
7824 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007825#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007826 case XML_DOCB_DOCUMENT_NODE:
7827#endif
7828 case XML_HTML_DOCUMENT_NODE:
7829 if (cur != start)
7830 return(cur);
7831 return(xmlDocGetRootElement((xmlDocPtr) cur));
7832 default:
7833 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007834 }
7835
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007836next_sibling:
7837 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007838 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007839 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007840 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007841 } else {
7842 cur = cur->parent;
7843 goto next_sibling;
7844 }
7845 }
7846 }
7847 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007848}
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007849
7850/**
Owen Taylor3473f882001-02-23 17:55:21 +00007851 * xmlXPathNextDescendant:
7852 * @ctxt: the XPath Parser context
7853 * @cur: the current node in the traversal
7854 *
7855 * Traversal function for the "descendant" direction
7856 * the descendant axis contains the descendants of the context node in document
7857 * order; a descendant is a child or a child of a child and so on.
7858 *
7859 * Returns the next element following that axis
7860 */
7861xmlNodePtr
7862xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007863 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007864 if (cur == NULL) {
7865 if (ctxt->context->node == NULL)
7866 return(NULL);
7867 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7868 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7869 return(NULL);
7870
7871 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7872 return(ctxt->context->doc->children);
7873 return(ctxt->context->node->children);
7874 }
7875
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007876 if (cur->type == XML_NAMESPACE_DECL)
7877 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007878 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007879 /*
7880 * Do not descend on entities declarations
7881 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007882 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007883 cur = cur->children;
7884 /*
7885 * Skip DTDs
7886 */
7887 if (cur->type != XML_DTD_NODE)
7888 return(cur);
7889 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007890 }
7891
7892 if (cur == ctxt->context->node) return(NULL);
7893
Daniel Veillard68e9e742002-11-16 15:35:11 +00007894 while (cur->next != NULL) {
7895 cur = cur->next;
7896 if ((cur->type != XML_ENTITY_DECL) &&
7897 (cur->type != XML_DTD_NODE))
7898 return(cur);
7899 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007900
Owen Taylor3473f882001-02-23 17:55:21 +00007901 do {
7902 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007903 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007904 if (cur == ctxt->context->node) return(NULL);
7905 if (cur->next != NULL) {
7906 cur = cur->next;
7907 return(cur);
7908 }
7909 } while (cur != NULL);
7910 return(cur);
7911}
7912
7913/**
7914 * xmlXPathNextDescendantOrSelf:
7915 * @ctxt: the XPath Parser context
7916 * @cur: the current node in the traversal
7917 *
7918 * Traversal function for the "descendant-or-self" direction
7919 * the descendant-or-self axis contains the context node and the descendants
7920 * of the context node in document order; thus the context node is the first
7921 * node on the axis, and the first child of the context node is the second node
7922 * on the axis
7923 *
7924 * Returns the next element following that axis
7925 */
7926xmlNodePtr
7927xmlXPathNextDescendantOrSelf(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 if (cur == NULL) {
7930 if (ctxt->context->node == NULL)
7931 return(NULL);
7932 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7933 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7934 return(NULL);
7935 return(ctxt->context->node);
7936 }
7937
7938 return(xmlXPathNextDescendant(ctxt, cur));
7939}
7940
7941/**
7942 * xmlXPathNextParent:
7943 * @ctxt: the XPath Parser context
7944 * @cur: the current node in the traversal
7945 *
7946 * Traversal function for the "parent" direction
7947 * The parent axis contains the parent of the context node, if there is one.
7948 *
7949 * Returns the next element following that axis
7950 */
7951xmlNodePtr
7952xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007953 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007954 /*
7955 * the parent of an attribute or namespace node is the element
7956 * to which the attribute or namespace node is attached
7957 * Namespace handling !!!
7958 */
7959 if (cur == NULL) {
7960 if (ctxt->context->node == NULL) return(NULL);
7961 switch (ctxt->context->node->type) {
7962 case XML_ELEMENT_NODE:
7963 case XML_TEXT_NODE:
7964 case XML_CDATA_SECTION_NODE:
7965 case XML_ENTITY_REF_NODE:
7966 case XML_ENTITY_NODE:
7967 case XML_PI_NODE:
7968 case XML_COMMENT_NODE:
7969 case XML_NOTATION_NODE:
7970 case XML_DTD_NODE:
7971 case XML_ELEMENT_DECL:
7972 case XML_ATTRIBUTE_DECL:
7973 case XML_XINCLUDE_START:
7974 case XML_XINCLUDE_END:
7975 case XML_ENTITY_DECL:
7976 if (ctxt->context->node->parent == NULL)
7977 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007978 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007979 ((ctxt->context->node->parent->name[0] == ' ') ||
7980 (xmlStrEqual(ctxt->context->node->parent->name,
7981 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007982 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007983 return(ctxt->context->node->parent);
7984 case XML_ATTRIBUTE_NODE: {
7985 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7986
7987 return(att->parent);
7988 }
7989 case XML_DOCUMENT_NODE:
7990 case XML_DOCUMENT_TYPE_NODE:
7991 case XML_DOCUMENT_FRAG_NODE:
7992 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007993#ifdef LIBXML_DOCB_ENABLED
7994 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007995#endif
7996 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007997 case XML_NAMESPACE_DECL: {
7998 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007999
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008000 if ((ns->next != NULL) &&
8001 (ns->next->type != XML_NAMESPACE_DECL))
8002 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00008003 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008004 }
Owen Taylor3473f882001-02-23 17:55:21 +00008005 }
8006 }
8007 return(NULL);
8008}
8009
8010/**
8011 * xmlXPathNextAncestor:
8012 * @ctxt: the XPath Parser context
8013 * @cur: the current node in the traversal
8014 *
8015 * Traversal function for the "ancestor" direction
8016 * the ancestor axis contains the ancestors of the context node; the ancestors
8017 * of the context node consist of the parent of context node and the parent's
8018 * parent and so on; the nodes are ordered in reverse document order; thus the
8019 * parent is the first node on the axis, and the parent's parent is the second
8020 * node on the axis
8021 *
8022 * Returns the next element following that axis
8023 */
8024xmlNodePtr
8025xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008026 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008027 /*
8028 * the parent of an attribute or namespace node is the element
8029 * to which the attribute or namespace node is attached
8030 * !!!!!!!!!!!!!
8031 */
8032 if (cur == NULL) {
8033 if (ctxt->context->node == NULL) return(NULL);
8034 switch (ctxt->context->node->type) {
8035 case XML_ELEMENT_NODE:
8036 case XML_TEXT_NODE:
8037 case XML_CDATA_SECTION_NODE:
8038 case XML_ENTITY_REF_NODE:
8039 case XML_ENTITY_NODE:
8040 case XML_PI_NODE:
8041 case XML_COMMENT_NODE:
8042 case XML_DTD_NODE:
8043 case XML_ELEMENT_DECL:
8044 case XML_ATTRIBUTE_DECL:
8045 case XML_ENTITY_DECL:
8046 case XML_NOTATION_NODE:
8047 case XML_XINCLUDE_START:
8048 case XML_XINCLUDE_END:
8049 if (ctxt->context->node->parent == NULL)
8050 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008051 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008052 ((ctxt->context->node->parent->name[0] == ' ') ||
8053 (xmlStrEqual(ctxt->context->node->parent->name,
8054 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008055 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008056 return(ctxt->context->node->parent);
8057 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008058 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00008059
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008060 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00008061 }
8062 case XML_DOCUMENT_NODE:
8063 case XML_DOCUMENT_TYPE_NODE:
8064 case XML_DOCUMENT_FRAG_NODE:
8065 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008066#ifdef LIBXML_DOCB_ENABLED
8067 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008068#endif
8069 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008070 case XML_NAMESPACE_DECL: {
8071 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008072
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008073 if ((ns->next != NULL) &&
8074 (ns->next->type != XML_NAMESPACE_DECL))
8075 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008076 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008077 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008078 }
Owen Taylor3473f882001-02-23 17:55:21 +00008079 }
8080 return(NULL);
8081 }
8082 if (cur == ctxt->context->doc->children)
8083 return((xmlNodePtr) ctxt->context->doc);
8084 if (cur == (xmlNodePtr) ctxt->context->doc)
8085 return(NULL);
8086 switch (cur->type) {
8087 case XML_ELEMENT_NODE:
8088 case XML_TEXT_NODE:
8089 case XML_CDATA_SECTION_NODE:
8090 case XML_ENTITY_REF_NODE:
8091 case XML_ENTITY_NODE:
8092 case XML_PI_NODE:
8093 case XML_COMMENT_NODE:
8094 case XML_NOTATION_NODE:
8095 case XML_DTD_NODE:
8096 case XML_ELEMENT_DECL:
8097 case XML_ATTRIBUTE_DECL:
8098 case XML_ENTITY_DECL:
8099 case XML_XINCLUDE_START:
8100 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008101 if (cur->parent == NULL)
8102 return(NULL);
8103 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008104 ((cur->parent->name[0] == ' ') ||
8105 (xmlStrEqual(cur->parent->name,
8106 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008107 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008108 return(cur->parent);
8109 case XML_ATTRIBUTE_NODE: {
8110 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8111
8112 return(att->parent);
8113 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008114 case XML_NAMESPACE_DECL: {
8115 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008116
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008117 if ((ns->next != NULL) &&
8118 (ns->next->type != XML_NAMESPACE_DECL))
8119 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008120 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008121 return(NULL);
8122 }
Owen Taylor3473f882001-02-23 17:55:21 +00008123 case XML_DOCUMENT_NODE:
8124 case XML_DOCUMENT_TYPE_NODE:
8125 case XML_DOCUMENT_FRAG_NODE:
8126 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008127#ifdef LIBXML_DOCB_ENABLED
8128 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008129#endif
8130 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008131 }
8132 return(NULL);
8133}
8134
8135/**
8136 * xmlXPathNextAncestorOrSelf:
8137 * @ctxt: the XPath Parser context
8138 * @cur: the current node in the traversal
8139 *
8140 * Traversal function for the "ancestor-or-self" direction
8141 * he ancestor-or-self axis contains the context node and ancestors of
8142 * the context node in reverse document order; thus the context node is
8143 * the first node on the axis, and the context node's parent the second;
8144 * parent here is defined the same as with the parent axis.
8145 *
8146 * Returns the next element following that axis
8147 */
8148xmlNodePtr
8149xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008150 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008151 if (cur == NULL)
8152 return(ctxt->context->node);
8153 return(xmlXPathNextAncestor(ctxt, cur));
8154}
8155
8156/**
8157 * xmlXPathNextFollowingSibling:
8158 * @ctxt: the XPath Parser context
8159 * @cur: the current node in the traversal
8160 *
8161 * Traversal function for the "following-sibling" direction
8162 * The following-sibling axis contains the following siblings of the context
8163 * node in document order.
8164 *
8165 * Returns the next element following that axis
8166 */
8167xmlNodePtr
8168xmlXPathNextFollowingSibling(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->next);
8177 return(cur->next);
8178}
8179
8180/**
8181 * xmlXPathNextPrecedingSibling:
8182 * @ctxt: the XPath Parser context
8183 * @cur: the current node in the traversal
8184 *
8185 * Traversal function for the "preceding-sibling" direction
8186 * The preceding-sibling axis contains the preceding siblings of the context
8187 * node in reverse document order; the first preceding sibling is first on the
8188 * axis; the sibling preceding that node is the second on the axis and so on.
8189 *
8190 * Returns the next element following that axis
8191 */
8192xmlNodePtr
8193xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008194 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008195 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8196 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8197 return(NULL);
8198 if (cur == (xmlNodePtr) ctxt->context->doc)
8199 return(NULL);
8200 if (cur == NULL)
8201 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008202 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8203 cur = cur->prev;
8204 if (cur == NULL)
8205 return(ctxt->context->node->prev);
8206 }
Owen Taylor3473f882001-02-23 17:55:21 +00008207 return(cur->prev);
8208}
8209
8210/**
8211 * xmlXPathNextFollowing:
8212 * @ctxt: the XPath Parser context
8213 * @cur: the current node in the traversal
8214 *
8215 * Traversal function for the "following" direction
8216 * The following axis contains all nodes in the same document as the context
8217 * node that are after the context node in document order, excluding any
8218 * descendants and excluding attribute nodes and namespace nodes; the nodes
8219 * are ordered in document order
8220 *
8221 * Returns the next element following that axis
8222 */
8223xmlNodePtr
8224xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008225 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008226 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8227 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8228 return(cur->children);
8229
8230 if (cur == NULL) {
8231 cur = ctxt->context->node;
8232 if (cur->type == XML_NAMESPACE_DECL)
Daniel Veillard91d19752010-10-15 14:30:52 +02008233 return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008234 if (cur->type == XML_ATTRIBUTE_NODE)
8235 cur = cur->parent;
Daniel Veillard91d19752010-10-15 14:30:52 +02008236 }
Owen Taylor3473f882001-02-23 17:55:21 +00008237 if (cur == NULL) return(NULL) ; /* ERROR */
8238 if (cur->next != NULL) return(cur->next) ;
8239 do {
8240 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008241 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008242 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8243 if (cur->next != NULL) return(cur->next);
8244 } while (cur != NULL);
8245 return(cur);
8246}
8247
8248/*
8249 * xmlXPathIsAncestor:
8250 * @ancestor: the ancestor node
8251 * @node: the current node
8252 *
8253 * Check that @ancestor is a @node's ancestor
8254 *
8255 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8256 */
8257static int
8258xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8259 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008260 if (node->type == XML_NAMESPACE_DECL)
8261 return(0);
8262 if (ancestor->type == XML_NAMESPACE_DECL)
8263 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008264 /* nodes need to be in the same document */
8265 if (ancestor->doc != node->doc) return(0);
8266 /* avoid searching if ancestor or node is the root node */
8267 if (ancestor == (xmlNodePtr) node->doc) return(1);
8268 if (node == (xmlNodePtr) ancestor->doc) return(0);
8269 while (node->parent != NULL) {
8270 if (node->parent == ancestor)
8271 return(1);
8272 node = node->parent;
8273 }
8274 return(0);
8275}
8276
8277/**
8278 * xmlXPathNextPreceding:
8279 * @ctxt: the XPath Parser context
8280 * @cur: the current node in the traversal
8281 *
8282 * Traversal function for the "preceding" direction
8283 * the preceding axis contains all nodes in the same document as the context
8284 * node that are before the context node in document order, excluding any
8285 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8286 * ordered in reverse document order
8287 *
8288 * Returns the next element following that axis
8289 */
8290xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008291xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8292{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008293 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008294 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008295 cur = ctxt->context->node;
Daniel Veillardea90b892010-10-22 15:50:50 +02008296 if (cur->type == XML_NAMESPACE_DECL)
8297 return(NULL);
8298 if (cur->type == XML_ATTRIBUTE_NODE)
8299 return(cur->parent);
8300 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008301 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008302 return (NULL);
8303 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8304 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008305 do {
8306 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008307 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8308 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008309 }
8310
8311 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008312 if (cur == NULL)
8313 return (NULL);
8314 if (cur == ctxt->context->doc->children)
8315 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008316 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008317 return (cur);
8318}
8319
8320/**
8321 * xmlXPathNextPrecedingInternal:
8322 * @ctxt: the XPath Parser context
8323 * @cur: the current node in the traversal
8324 *
8325 * Traversal function for the "preceding" direction
8326 * the preceding axis contains all nodes in the same document as the context
8327 * node that are before the context node in document order, excluding any
8328 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8329 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008330 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008331 * state kept in the parser context: ctxt->ancestor.
8332 *
8333 * Returns the next element following that axis
8334 */
8335static xmlNodePtr
8336xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8337 xmlNodePtr cur)
8338{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008339 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008340 if (cur == NULL) {
8341 cur = ctxt->context->node;
8342 if (cur == NULL)
8343 return (NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008344 if (cur->type == XML_NAMESPACE_DECL)
8345 return (NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008346 ctxt->ancestor = cur->parent;
8347 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008348 if (cur->type == XML_NAMESPACE_DECL)
8349 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008350 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8351 cur = cur->prev;
8352 while (cur->prev == NULL) {
8353 cur = cur->parent;
8354 if (cur == NULL)
8355 return (NULL);
8356 if (cur == ctxt->context->doc->children)
8357 return (NULL);
8358 if (cur != ctxt->ancestor)
8359 return (cur);
8360 ctxt->ancestor = cur->parent;
8361 }
8362 cur = cur->prev;
8363 while (cur->last != NULL)
8364 cur = cur->last;
8365 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008366}
8367
8368/**
8369 * xmlXPathNextNamespace:
8370 * @ctxt: the XPath Parser context
8371 * @cur: the current attribute in the traversal
8372 *
8373 * Traversal function for the "namespace" direction
8374 * the namespace axis contains the namespace nodes of the context node;
8375 * the order of nodes on this axis is implementation-defined; the axis will
8376 * be empty unless the context node is an element
8377 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008378 * We keep the XML namespace node at the end of the list.
8379 *
Owen Taylor3473f882001-02-23 17:55:21 +00008380 * Returns the next element following that axis
8381 */
8382xmlNodePtr
8383xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008384 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008385 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008386 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008387 if (ctxt->context->tmpNsList != NULL)
8388 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008389 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008390 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008391 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008392 if (ctxt->context->tmpNsList != NULL) {
8393 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8394 ctxt->context->tmpNsNr++;
8395 }
8396 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008397 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008398 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008399 if (ctxt->context->tmpNsNr > 0) {
8400 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8401 } else {
8402 if (ctxt->context->tmpNsList != NULL)
8403 xmlFree(ctxt->context->tmpNsList);
8404 ctxt->context->tmpNsList = NULL;
8405 return(NULL);
8406 }
Owen Taylor3473f882001-02-23 17:55:21 +00008407}
8408
8409/**
8410 * xmlXPathNextAttribute:
8411 * @ctxt: the XPath Parser context
8412 * @cur: the current attribute in the traversal
8413 *
8414 * Traversal function for the "attribute" direction
8415 * TODO: support DTD inherited default attributes
8416 *
8417 * Returns the next element following that axis
8418 */
8419xmlNodePtr
8420xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008421 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008422 if (ctxt->context->node == NULL)
8423 return(NULL);
8424 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8425 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008426 if (cur == NULL) {
8427 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8428 return(NULL);
8429 return((xmlNodePtr)ctxt->context->node->properties);
8430 }
8431 return((xmlNodePtr)cur->next);
8432}
8433
8434/************************************************************************
8435 * *
8436 * NodeTest Functions *
8437 * *
8438 ************************************************************************/
8439
Owen Taylor3473f882001-02-23 17:55:21 +00008440#define IS_FUNCTION 200
8441
Owen Taylor3473f882001-02-23 17:55:21 +00008442
8443/************************************************************************
8444 * *
8445 * Implicit tree core function library *
8446 * *
8447 ************************************************************************/
8448
8449/**
8450 * xmlXPathRoot:
8451 * @ctxt: the XPath Parser context
8452 *
8453 * Initialize the context to the root of the document
8454 */
8455void
8456xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008457 if ((ctxt == NULL) || (ctxt->context == NULL))
8458 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008459 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008460 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8461 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008462}
8463
8464/************************************************************************
8465 * *
8466 * The explicit core function library *
8467 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8468 * *
8469 ************************************************************************/
8470
8471
8472/**
8473 * xmlXPathLastFunction:
8474 * @ctxt: the XPath Parser context
8475 * @nargs: the number of arguments
8476 *
8477 * Implement the last() XPath function
8478 * number last()
8479 * The last function returns the number of nodes in the context node list.
8480 */
8481void
8482xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8483 CHECK_ARITY(0);
8484 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008485 valuePush(ctxt,
8486 xmlXPathCacheNewFloat(ctxt->context,
8487 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008488#ifdef DEBUG_EXPR
8489 xmlGenericError(xmlGenericErrorContext,
8490 "last() : %d\n", ctxt->context->contextSize);
8491#endif
8492 } else {
8493 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8494 }
8495}
8496
8497/**
8498 * xmlXPathPositionFunction:
8499 * @ctxt: the XPath Parser context
8500 * @nargs: the number of arguments
8501 *
8502 * Implement the position() XPath function
8503 * number position()
8504 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008505 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008506 * will be equal to last().
8507 */
8508void
8509xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8510 CHECK_ARITY(0);
8511 if (ctxt->context->proximityPosition >= 0) {
8512 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008513 xmlXPathCacheNewFloat(ctxt->context,
8514 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008515#ifdef DEBUG_EXPR
8516 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8517 ctxt->context->proximityPosition);
8518#endif
8519 } else {
8520 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8521 }
8522}
8523
8524/**
8525 * xmlXPathCountFunction:
8526 * @ctxt: the XPath Parser context
8527 * @nargs: the number of arguments
8528 *
8529 * Implement the count() XPath function
8530 * number count(node-set)
8531 */
8532void
8533xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8534 xmlXPathObjectPtr cur;
8535
8536 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008537 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008538 ((ctxt->value->type != XPATH_NODESET) &&
8539 (ctxt->value->type != XPATH_XSLT_TREE)))
8540 XP_ERROR(XPATH_INVALID_TYPE);
8541 cur = valuePop(ctxt);
8542
Daniel Veillard911f49a2001-04-07 15:39:35 +00008543 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008544 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008545 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008546 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8547 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008548 } else {
8549 if ((cur->nodesetval->nodeNr != 1) ||
8550 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008551 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008552 } else {
8553 xmlNodePtr tmp;
8554 int i = 0;
8555
8556 tmp = cur->nodesetval->nodeTab[0];
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008557 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
Daniel Veillardfe703322001-08-14 12:18:09 +00008558 tmp = tmp->children;
8559 while (tmp != NULL) {
8560 tmp = tmp->next;
8561 i++;
8562 }
8563 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008564 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008565 }
8566 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008567 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008568}
8569
8570/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008571 * xmlXPathGetElementsByIds:
8572 * @doc: the document
8573 * @ids: a whitespace separated list of IDs
8574 *
8575 * Selects elements by their unique ID.
8576 *
8577 * Returns a node-set of selected elements.
8578 */
8579static xmlNodeSetPtr
8580xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8581 xmlNodeSetPtr ret;
8582 const xmlChar *cur = ids;
8583 xmlChar *ID;
8584 xmlAttrPtr attr;
8585 xmlNodePtr elem = NULL;
8586
Daniel Veillard7a985a12003-07-06 17:57:42 +00008587 if (ids == NULL) return(NULL);
8588
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008589 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008590 if (ret == NULL)
8591 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008592
William M. Brack76e95df2003-10-18 16:20:14 +00008593 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008594 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008595 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008596 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008597
8598 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008599 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008600 /*
8601 * We used to check the fact that the value passed
8602 * was an NCName, but this generated much troubles for
8603 * me and Aleksey Sanin, people blatantly violated that
8604 * constaint, like Visa3D spec.
8605 * if (xmlValidateNCName(ID, 1) == 0)
8606 */
8607 attr = xmlGetID(doc, ID);
8608 if (attr != NULL) {
8609 if (attr->type == XML_ATTRIBUTE_NODE)
8610 elem = attr->parent;
8611 else if (attr->type == XML_ELEMENT_NODE)
8612 elem = (xmlNodePtr) attr;
8613 else
8614 elem = NULL;
8615 if (elem != NULL)
8616 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008617 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008618 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008619 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008620
William M. Brack76e95df2003-10-18 16:20:14 +00008621 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008622 ids = cur;
8623 }
8624 return(ret);
8625}
8626
8627/**
Owen Taylor3473f882001-02-23 17:55:21 +00008628 * xmlXPathIdFunction:
8629 * @ctxt: the XPath Parser context
8630 * @nargs: the number of arguments
8631 *
8632 * Implement the id() XPath function
8633 * node-set id(object)
8634 * The id function selects elements by their unique ID
8635 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8636 * then the result is the union of the result of applying id to the
8637 * string value of each of the nodes in the argument node-set. When the
8638 * argument to id is of any other type, the argument is converted to a
8639 * string as if by a call to the string function; the string is split
8640 * into a whitespace-separated list of tokens (whitespace is any sequence
8641 * of characters matching the production S); the result is a node-set
8642 * containing the elements in the same document as the context node that
8643 * have a unique ID equal to any of the tokens in the list.
8644 */
8645void
8646xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008647 xmlChar *tokens;
8648 xmlNodeSetPtr ret;
8649 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008650
8651 CHECK_ARITY(1);
8652 obj = valuePop(ctxt);
8653 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008654 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008655 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008656 int i;
8657
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008658 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008659 /*
8660 * FIXME -- in an out-of-memory condition this will behave badly.
8661 * The solution is not clear -- we already popped an item from
8662 * ctxt, so the object is in a corrupt state.
8663 */
Owen Taylor3473f882001-02-23 17:55:21 +00008664
Daniel Veillard911f49a2001-04-07 15:39:35 +00008665 if (obj->nodesetval != NULL) {
8666 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008667 tokens =
8668 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8669 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8670 ret = xmlXPathNodeSetMerge(ret, ns);
8671 xmlXPathFreeNodeSet(ns);
8672 if (tokens != NULL)
8673 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008674 }
Owen Taylor3473f882001-02-23 17:55:21 +00008675 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008676 xmlXPathReleaseObject(ctxt->context, obj);
8677 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008678 return;
8679 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008680 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008681 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008682 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008683 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008684 return;
8685}
8686
8687/**
8688 * xmlXPathLocalNameFunction:
8689 * @ctxt: the XPath Parser context
8690 * @nargs: the number of arguments
8691 *
8692 * Implement the local-name() XPath function
8693 * string local-name(node-set?)
8694 * The local-name function returns a string containing the local part
8695 * of the name of the node in the argument node-set that is first in
8696 * document order. If the node-set is empty or the first node has no
8697 * name, an empty string is returned. If the argument is omitted it
8698 * defaults to the context node.
8699 */
8700void
8701xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8702 xmlXPathObjectPtr cur;
8703
Daniel Veillarda82b1822004-11-08 16:24:57 +00008704 if (ctxt == NULL) return;
8705
Owen Taylor3473f882001-02-23 17:55:21 +00008706 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008707 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8708 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008709 nargs = 1;
8710 }
8711
8712 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008713 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008714 ((ctxt->value->type != XPATH_NODESET) &&
8715 (ctxt->value->type != XPATH_XSLT_TREE)))
8716 XP_ERROR(XPATH_INVALID_TYPE);
8717 cur = valuePop(ctxt);
8718
Daniel Veillard911f49a2001-04-07 15:39:35 +00008719 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008720 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008721 } else {
8722 int i = 0; /* Should be first in document order !!!!! */
8723 switch (cur->nodesetval->nodeTab[i]->type) {
8724 case XML_ELEMENT_NODE:
8725 case XML_ATTRIBUTE_NODE:
8726 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008727 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008728 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008729 else
8730 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008731 xmlXPathCacheNewString(ctxt->context,
8732 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008733 break;
8734 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008735 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008736 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8737 break;
8738 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008739 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008740 }
8741 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008742 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008743}
8744
8745/**
8746 * xmlXPathNamespaceURIFunction:
8747 * @ctxt: the XPath Parser context
8748 * @nargs: the number of arguments
8749 *
8750 * Implement the namespace-uri() XPath function
8751 * string namespace-uri(node-set?)
8752 * The namespace-uri function returns a string containing the
8753 * namespace URI of the expanded name of the node in the argument
8754 * node-set that is first in document order. If the node-set is empty,
8755 * the first node has no name, or the expanded name has no namespace
8756 * URI, an empty string is returned. If the argument is omitted it
8757 * defaults to the context node.
8758 */
8759void
8760xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8761 xmlXPathObjectPtr cur;
8762
Daniel Veillarda82b1822004-11-08 16:24:57 +00008763 if (ctxt == NULL) return;
8764
Owen Taylor3473f882001-02-23 17:55:21 +00008765 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008766 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8767 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008768 nargs = 1;
8769 }
8770 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008771 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008772 ((ctxt->value->type != XPATH_NODESET) &&
8773 (ctxt->value->type != XPATH_XSLT_TREE)))
8774 XP_ERROR(XPATH_INVALID_TYPE);
8775 cur = valuePop(ctxt);
8776
Daniel Veillard911f49a2001-04-07 15:39:35 +00008777 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008778 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008779 } else {
8780 int i = 0; /* Should be first in document order !!!!! */
8781 switch (cur->nodesetval->nodeTab[i]->type) {
8782 case XML_ELEMENT_NODE:
8783 case XML_ATTRIBUTE_NODE:
8784 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008785 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008786 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008787 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008788 cur->nodesetval->nodeTab[i]->ns->href));
8789 break;
8790 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008791 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008792 }
8793 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008794 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008795}
8796
8797/**
8798 * xmlXPathNameFunction:
8799 * @ctxt: the XPath Parser context
8800 * @nargs: the number of arguments
8801 *
8802 * Implement the name() XPath function
8803 * string name(node-set?)
8804 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008805 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008806 * order. The QName must represent the name with respect to the namespace
8807 * declarations in effect on the node whose name is being represented.
8808 * Typically, this will be the form in which the name occurred in the XML
8809 * source. This need not be the case if there are namespace declarations
8810 * in effect on the node that associate multiple prefixes with the same
8811 * namespace. However, an implementation may include information about
8812 * the original prefix in its representation of nodes; in this case, an
8813 * implementation can ensure that the returned string is always the same
8814 * as the QName used in the XML source. If the argument it omitted it
8815 * defaults to the context node.
8816 * Libxml keep the original prefix so the "real qualified name" used is
8817 * returned.
8818 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008819static void
Daniel Veillard04383752001-07-08 14:27:15 +00008820xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8821{
Owen Taylor3473f882001-02-23 17:55:21 +00008822 xmlXPathObjectPtr cur;
8823
8824 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008825 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8826 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008827 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008828 }
8829
8830 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008831 if ((ctxt->value == NULL) ||
8832 ((ctxt->value->type != XPATH_NODESET) &&
8833 (ctxt->value->type != XPATH_XSLT_TREE)))
8834 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008835 cur = valuePop(ctxt);
8836
Daniel Veillard911f49a2001-04-07 15:39:35 +00008837 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008838 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008839 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008840 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008841
Daniel Veillard04383752001-07-08 14:27:15 +00008842 switch (cur->nodesetval->nodeTab[i]->type) {
8843 case XML_ELEMENT_NODE:
8844 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008845 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008846 valuePush(ctxt,
8847 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008848 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8849 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008850 valuePush(ctxt,
8851 xmlXPathCacheNewString(ctxt->context,
8852 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008853 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008854 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008855
Daniel Veillardc00cda82003-04-07 10:22:39 +00008856 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8857 cur->nodesetval->nodeTab[i]->ns->prefix,
8858 NULL, 0);
8859 if (fullname == cur->nodesetval->nodeTab[i]->name)
8860 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8861 if (fullname == NULL) {
8862 XP_ERROR(XPATH_MEMORY_ERROR);
8863 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008864 valuePush(ctxt, xmlXPathCacheWrapString(
8865 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008866 }
8867 break;
8868 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008869 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8870 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008871 xmlXPathLocalNameFunction(ctxt, 1);
8872 }
Owen Taylor3473f882001-02-23 17:55:21 +00008873 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008874 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008875}
8876
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008877
8878/**
Owen Taylor3473f882001-02-23 17:55:21 +00008879 * xmlXPathStringFunction:
8880 * @ctxt: the XPath Parser context
8881 * @nargs: the number of arguments
8882 *
8883 * Implement the string() XPath function
8884 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008885 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008886 * - A node-set is converted to a string by returning the value of
8887 * the node in the node-set that is first in document order.
8888 * If the node-set is empty, an empty string is returned.
8889 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008890 * + NaN is converted to the string NaN
8891 * + positive zero is converted to the string 0
8892 * + negative zero is converted to the string 0
8893 * + positive infinity is converted to the string Infinity
8894 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008895 * + if the number is an integer, the number is represented in
8896 * decimal form as a Number with no decimal point and no leading
8897 * zeros, preceded by a minus sign (-) if the number is negative
8898 * + otherwise, the number is represented in decimal form as a
8899 * Number including a decimal point with at least one digit
8900 * before the decimal point and at least one digit after the
8901 * decimal point, preceded by a minus sign (-) if the number
8902 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008903 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008904 * before the decimal point; beyond the one required digit
8905 * after the decimal point there must be as many, but only as
8906 * many, more digits as are needed to uniquely distinguish the
8907 * number from all other IEEE 754 numeric values.
8908 * - The boolean false value is converted to the string false.
8909 * The boolean true value is converted to the string true.
8910 *
8911 * If the argument is omitted, it defaults to a node-set with the
8912 * context node as its only member.
8913 */
8914void
8915xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8916 xmlXPathObjectPtr cur;
8917
Daniel Veillarda82b1822004-11-08 16:24:57 +00008918 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008919 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008920 valuePush(ctxt,
8921 xmlXPathCacheWrapString(ctxt->context,
8922 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008923 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008924 }
8925
8926 CHECK_ARITY(1);
8927 cur = valuePop(ctxt);
8928 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008929 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008930}
8931
8932/**
8933 * xmlXPathStringLengthFunction:
8934 * @ctxt: the XPath Parser context
8935 * @nargs: the number of arguments
8936 *
8937 * Implement the string-length() XPath function
8938 * number string-length(string?)
8939 * The string-length returns the number of characters in the string
8940 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8941 * the context node converted to a string, in other words the value
8942 * of the context node.
8943 */
8944void
8945xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8946 xmlXPathObjectPtr cur;
8947
8948 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008949 if ((ctxt == NULL) || (ctxt->context == NULL))
8950 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008951 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008952 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008953 } else {
8954 xmlChar *content;
8955
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008956 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008957 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8958 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008959 xmlFree(content);
8960 }
8961 return;
8962 }
8963 CHECK_ARITY(1);
8964 CAST_TO_STRING;
8965 CHECK_TYPE(XPATH_STRING);
8966 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008967 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008968 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008969 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008970}
8971
8972/**
8973 * xmlXPathConcatFunction:
8974 * @ctxt: the XPath Parser context
8975 * @nargs: the number of arguments
8976 *
8977 * Implement the concat() XPath function
8978 * string concat(string, string, string*)
8979 * The concat function returns the concatenation of its arguments.
8980 */
8981void
8982xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8983 xmlXPathObjectPtr cur, newobj;
8984 xmlChar *tmp;
8985
Daniel Veillarda82b1822004-11-08 16:24:57 +00008986 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008987 if (nargs < 2) {
8988 CHECK_ARITY(2);
8989 }
8990
8991 CAST_TO_STRING;
8992 cur = valuePop(ctxt);
8993 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008994 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008995 return;
8996 }
8997 nargs--;
8998
8999 while (nargs > 0) {
9000 CAST_TO_STRING;
9001 newobj = valuePop(ctxt);
9002 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009003 xmlXPathReleaseObject(ctxt->context, newobj);
9004 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009005 XP_ERROR(XPATH_INVALID_TYPE);
9006 }
9007 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9008 newobj->stringval = cur->stringval;
9009 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009010 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00009011 nargs--;
9012 }
9013 valuePush(ctxt, cur);
9014}
9015
9016/**
9017 * xmlXPathContainsFunction:
9018 * @ctxt: the XPath Parser context
9019 * @nargs: the number of arguments
9020 *
9021 * Implement the contains() XPath function
9022 * boolean contains(string, string)
9023 * The contains function returns true if the first argument string
9024 * contains the second argument string, and otherwise returns false.
9025 */
9026void
9027xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9028 xmlXPathObjectPtr hay, needle;
9029
9030 CHECK_ARITY(2);
9031 CAST_TO_STRING;
9032 CHECK_TYPE(XPATH_STRING);
9033 needle = valuePop(ctxt);
9034 CAST_TO_STRING;
9035 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009036
Owen Taylor3473f882001-02-23 17:55:21 +00009037 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009038 xmlXPathReleaseObject(ctxt->context, hay);
9039 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009040 XP_ERROR(XPATH_INVALID_TYPE);
9041 }
9042 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009043 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009044 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009045 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9046 xmlXPathReleaseObject(ctxt->context, hay);
9047 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009048}
9049
9050/**
9051 * xmlXPathStartsWithFunction:
9052 * @ctxt: the XPath Parser context
9053 * @nargs: the number of arguments
9054 *
9055 * Implement the starts-with() XPath function
9056 * boolean starts-with(string, string)
9057 * The starts-with function returns true if the first argument string
9058 * starts with the second argument string, and otherwise returns false.
9059 */
9060void
9061xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9062 xmlXPathObjectPtr hay, needle;
9063 int n;
9064
9065 CHECK_ARITY(2);
9066 CAST_TO_STRING;
9067 CHECK_TYPE(XPATH_STRING);
9068 needle = valuePop(ctxt);
9069 CAST_TO_STRING;
9070 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009071
Owen Taylor3473f882001-02-23 17:55:21 +00009072 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009073 xmlXPathReleaseObject(ctxt->context, hay);
9074 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009075 XP_ERROR(XPATH_INVALID_TYPE);
9076 }
9077 n = xmlStrlen(needle->stringval);
9078 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009079 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009080 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009081 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9082 xmlXPathReleaseObject(ctxt->context, hay);
9083 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009084}
9085
9086/**
9087 * xmlXPathSubstringFunction:
9088 * @ctxt: the XPath Parser context
9089 * @nargs: the number of arguments
9090 *
9091 * Implement the substring() XPath function
9092 * string substring(string, number, number?)
9093 * The substring function returns the substring of the first argument
9094 * starting at the position specified in the second argument with
9095 * length specified in the third argument. For example,
9096 * substring("12345",2,3) returns "234". If the third argument is not
9097 * specified, it returns the substring starting at the position specified
9098 * in the second argument and continuing to the end of the string. For
9099 * example, substring("12345",2) returns "2345". More precisely, each
9100 * character in the string (see [3.6 Strings]) is considered to have a
9101 * numeric position: the position of the first character is 1, the position
9102 * of the second character is 2 and so on. The returned substring contains
9103 * those characters for which the position of the character is greater than
9104 * or equal to the second argument and, if the third argument is specified,
9105 * less than the sum of the second and third arguments; the comparisons
9106 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009107 * - substring("12345", 1.5, 2.6) returns "234"
9108 * - substring("12345", 0, 3) returns "12"
9109 * - substring("12345", 0 div 0, 3) returns ""
9110 * - substring("12345", 1, 0 div 0) returns ""
9111 * - substring("12345", -42, 1 div 0) returns "12345"
9112 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009113 */
9114void
9115xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9116 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009117 double le=0, in;
9118 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009119 xmlChar *ret;
9120
Owen Taylor3473f882001-02-23 17:55:21 +00009121 if (nargs < 2) {
9122 CHECK_ARITY(2);
9123 }
9124 if (nargs > 3) {
9125 CHECK_ARITY(3);
9126 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009127 /*
9128 * take care of possible last (position) argument
9129 */
Owen Taylor3473f882001-02-23 17:55:21 +00009130 if (nargs == 3) {
9131 CAST_TO_NUMBER;
9132 CHECK_TYPE(XPATH_NUMBER);
9133 len = valuePop(ctxt);
9134 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009135 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009136 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009137
Owen Taylor3473f882001-02-23 17:55:21 +00009138 CAST_TO_NUMBER;
9139 CHECK_TYPE(XPATH_NUMBER);
9140 start = valuePop(ctxt);
9141 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009142 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009143 CAST_TO_STRING;
9144 CHECK_TYPE(XPATH_STRING);
9145 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009146 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009147
Daniel Veillard97ac1312001-05-30 19:14:17 +00009148 /*
9149 * If last pos not present, calculate last position
9150 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009151 if (nargs != 3) {
9152 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009153 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009154 in = 1.0;
9155 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009156
Daniel Veillard45490ae2008-07-29 09:13:19 +00009157 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009158 * the index is NaN, the length is NaN, or both
9159 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009160 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009161 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009162 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009163 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009164 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009165 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009166 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009167 * First we go to integer form, rounding up
9168 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009169 */
9170 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009171 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009172
Daniel Veillard9e412302002-06-10 15:59:44 +00009173 if (xmlXPathIsInf(le) == 1) {
9174 l = m;
9175 if (i < 1)
9176 i = 1;
9177 }
9178 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9179 l = 0;
9180 else {
9181 l = (int) le;
9182 if (((double)l)+0.5 <= le) l++;
9183 }
9184
9185 /* Now we normalize inidices */
9186 i -= 1;
9187 l += i;
9188 if (i < 0)
9189 i = 0;
9190 if (l > m)
9191 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009192
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009193 /* number of chars to copy */
9194 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009195
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009196 ret = xmlUTF8Strsub(str->stringval, i, l);
9197 }
9198 else {
9199 ret = NULL;
9200 }
Owen Taylor3473f882001-02-23 17:55:21 +00009201 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009202 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009203 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009204 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009205 xmlFree(ret);
9206 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009207 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009208}
9209
9210/**
9211 * xmlXPathSubstringBeforeFunction:
9212 * @ctxt: the XPath Parser context
9213 * @nargs: the number of arguments
9214 *
9215 * Implement the substring-before() XPath function
9216 * string substring-before(string, string)
9217 * The substring-before function returns the substring of the first
9218 * argument string that precedes the first occurrence of the second
9219 * argument string in the first argument string, or the empty string
9220 * if the first argument string does not contain the second argument
9221 * string. For example, substring-before("1999/04/01","/") returns 1999.
9222 */
9223void
9224xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9225 xmlXPathObjectPtr str;
9226 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009227 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009228 const xmlChar *point;
9229 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009230
Owen Taylor3473f882001-02-23 17:55:21 +00009231 CHECK_ARITY(2);
9232 CAST_TO_STRING;
9233 find = valuePop(ctxt);
9234 CAST_TO_STRING;
9235 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009236
Daniel Veillardade10f22012-07-12 09:43:27 +08009237 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009238 if (target) {
9239 point = xmlStrstr(str->stringval, find->stringval);
9240 if (point) {
9241 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009242 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009243 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009244 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009245 xmlBufContent(target)));
9246 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009247 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009248 xmlXPathReleaseObject(ctxt->context, str);
9249 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009250}
9251
9252/**
9253 * xmlXPathSubstringAfterFunction:
9254 * @ctxt: the XPath Parser context
9255 * @nargs: the number of arguments
9256 *
9257 * Implement the substring-after() XPath function
9258 * string substring-after(string, string)
9259 * The substring-after function returns the substring of the first
9260 * argument string that follows the first occurrence of the second
9261 * argument string in the first argument string, or the empty stringi
9262 * if the first argument string does not contain the second argument
9263 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9264 * and substring-after("1999/04/01","19") returns 99/04/01.
9265 */
9266void
9267xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9268 xmlXPathObjectPtr str;
9269 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009270 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009271 const xmlChar *point;
9272 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009273
Owen Taylor3473f882001-02-23 17:55:21 +00009274 CHECK_ARITY(2);
9275 CAST_TO_STRING;
9276 find = valuePop(ctxt);
9277 CAST_TO_STRING;
9278 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009279
Daniel Veillardade10f22012-07-12 09:43:27 +08009280 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009281 if (target) {
9282 point = xmlStrstr(str->stringval, find->stringval);
9283 if (point) {
9284 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009285 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009286 xmlStrlen(str->stringval) - offset);
9287 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009288 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009289 xmlBufContent(target)));
9290 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009291 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009292 xmlXPathReleaseObject(ctxt->context, str);
9293 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009294}
9295
9296/**
9297 * xmlXPathNormalizeFunction:
9298 * @ctxt: the XPath Parser context
9299 * @nargs: the number of arguments
9300 *
9301 * Implement the normalize-space() XPath function
9302 * string normalize-space(string?)
9303 * The normalize-space function returns the argument string with white
9304 * space normalized by stripping leading and trailing whitespace
9305 * and replacing sequences of whitespace characters by a single
9306 * space. Whitespace characters are the same allowed by the S production
9307 * in XML. If the argument is omitted, it defaults to the context
9308 * node converted to a string, in other words the value of the context node.
9309 */
9310void
9311xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9312 xmlXPathObjectPtr obj = NULL;
9313 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009314 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009315 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009316
Daniel Veillarda82b1822004-11-08 16:24:57 +00009317 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009318 if (nargs == 0) {
9319 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009320 valuePush(ctxt,
9321 xmlXPathCacheWrapString(ctxt->context,
9322 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009323 nargs = 1;
9324 }
9325
9326 CHECK_ARITY(1);
9327 CAST_TO_STRING;
9328 CHECK_TYPE(XPATH_STRING);
9329 obj = valuePop(ctxt);
9330 source = obj->stringval;
9331
Daniel Veillardade10f22012-07-12 09:43:27 +08009332 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009333 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009334
Owen Taylor3473f882001-02-23 17:55:21 +00009335 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009336 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009337 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009338
Owen Taylor3473f882001-02-23 17:55:21 +00009339 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9340 blank = 0;
9341 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009342 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009343 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009344 } else {
9345 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009346 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009347 blank = 0;
9348 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009349 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009350 }
9351 source++;
9352 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009353 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009354 xmlBufContent(target)));
9355 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009356 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009357 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009358}
9359
9360/**
9361 * xmlXPathTranslateFunction:
9362 * @ctxt: the XPath Parser context
9363 * @nargs: the number of arguments
9364 *
9365 * Implement the translate() XPath function
9366 * string translate(string, string, string)
9367 * The translate function returns the first argument string with
9368 * occurrences of characters in the second argument string replaced
9369 * by the character at the corresponding position in the third argument
9370 * string. For example, translate("bar","abc","ABC") returns the string
9371 * BAr. If there is a character in the second argument string with no
9372 * character at a corresponding position in the third argument string
9373 * (because the second argument string is longer than the third argument
9374 * string), then occurrences of that character in the first argument
9375 * string are removed. For example, translate("--aaa--","abc-","ABC")
9376 * returns "AAA". If a character occurs more than once in second
9377 * argument string, then the first occurrence determines the replacement
9378 * character. If the third argument string is longer than the second
9379 * argument string, then excess characters are ignored.
9380 */
9381void
9382xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009383 xmlXPathObjectPtr str;
9384 xmlXPathObjectPtr from;
9385 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009386 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009387 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009388 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009389 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009390 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009391
Daniel Veillarde043ee12001-04-16 14:08:07 +00009392 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009393
Daniel Veillarde043ee12001-04-16 14:08:07 +00009394 CAST_TO_STRING;
9395 to = valuePop(ctxt);
9396 CAST_TO_STRING;
9397 from = valuePop(ctxt);
9398 CAST_TO_STRING;
9399 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009400
Daniel Veillardade10f22012-07-12 09:43:27 +08009401 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009402 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009403 max = xmlUTF8Strlen(to->stringval);
9404 for (cptr = str->stringval; (ch=*cptr); ) {
9405 offset = xmlUTF8Strloc(from->stringval, cptr);
9406 if (offset >= 0) {
9407 if (offset < max) {
9408 point = xmlUTF8Strpos(to->stringval, offset);
9409 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009410 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009411 }
9412 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009413 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009414
9415 /* Step to next character in input */
9416 cptr++;
9417 if ( ch & 0x80 ) {
9418 /* if not simple ascii, verify proper format */
9419 if ( (ch & 0xc0) != 0xc0 ) {
9420 xmlGenericError(xmlGenericErrorContext,
9421 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009422 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009423 break;
9424 }
9425 /* then skip over remaining bytes for this char */
9426 while ( (ch <<= 1) & 0x80 )
9427 if ( (*cptr++ & 0xc0) != 0x80 ) {
9428 xmlGenericError(xmlGenericErrorContext,
9429 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009430 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009431 break;
9432 }
9433 if (ch & 0x80) /* must have had error encountered */
9434 break;
9435 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009436 }
Owen Taylor3473f882001-02-23 17:55:21 +00009437 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009438 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009439 xmlBufContent(target)));
9440 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009441 xmlXPathReleaseObject(ctxt->context, str);
9442 xmlXPathReleaseObject(ctxt->context, from);
9443 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009444}
9445
9446/**
9447 * xmlXPathBooleanFunction:
9448 * @ctxt: the XPath Parser context
9449 * @nargs: the number of arguments
9450 *
9451 * Implement the boolean() XPath function
9452 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009453 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009454 * - a number is true if and only if it is neither positive or
9455 * negative zero nor NaN
9456 * - a node-set is true if and only if it is non-empty
9457 * - a string is true if and only if its length is non-zero
9458 */
9459void
9460xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9461 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009462
9463 CHECK_ARITY(1);
9464 cur = valuePop(ctxt);
9465 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009466 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009467 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009468}
9469
9470/**
9471 * xmlXPathNotFunction:
9472 * @ctxt: the XPath Parser context
9473 * @nargs: the number of arguments
9474 *
9475 * Implement the not() XPath function
9476 * boolean not(boolean)
9477 * The not function returns true if its argument is false,
9478 * and false otherwise.
9479 */
9480void
9481xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9482 CHECK_ARITY(1);
9483 CAST_TO_BOOLEAN;
9484 CHECK_TYPE(XPATH_BOOLEAN);
9485 ctxt->value->boolval = ! ctxt->value->boolval;
9486}
9487
9488/**
9489 * xmlXPathTrueFunction:
9490 * @ctxt: the XPath Parser context
9491 * @nargs: the number of arguments
9492 *
9493 * Implement the true() XPath function
9494 * boolean true()
9495 */
9496void
9497xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009499 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009500}
9501
9502/**
9503 * xmlXPathFalseFunction:
9504 * @ctxt: the XPath Parser context
9505 * @nargs: the number of arguments
9506 *
9507 * Implement the false() XPath function
9508 * boolean false()
9509 */
9510void
9511xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9512 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009513 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009514}
9515
9516/**
9517 * xmlXPathLangFunction:
9518 * @ctxt: the XPath Parser context
9519 * @nargs: the number of arguments
9520 *
9521 * Implement the lang() XPath function
9522 * boolean lang(string)
9523 * The lang function returns true or false depending on whether the
9524 * language of the context node as specified by xml:lang attributes
9525 * is the same as or is a sublanguage of the language specified by
9526 * the argument string. The language of the context node is determined
9527 * by the value of the xml:lang attribute on the context node, or, if
9528 * the context node has no xml:lang attribute, by the value of the
9529 * xml:lang attribute on the nearest ancestor of the context node that
9530 * has an xml:lang attribute. If there is no such attribute, then lang
9531 * returns false. If there is such an attribute, then lang returns
9532 * true if the attribute value is equal to the argument ignoring case,
9533 * or if there is some suffix starting with - such that the attribute
9534 * value is equal to the argument ignoring that suffix of the attribute
9535 * value and ignoring case.
9536 */
9537void
9538xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009539 xmlXPathObjectPtr val = NULL;
9540 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009541 const xmlChar *lang;
9542 int ret = 0;
9543 int i;
9544
9545 CHECK_ARITY(1);
9546 CAST_TO_STRING;
9547 CHECK_TYPE(XPATH_STRING);
9548 val = valuePop(ctxt);
9549 lang = val->stringval;
9550 theLang = xmlNodeGetLang(ctxt->context->node);
9551 if ((theLang != NULL) && (lang != NULL)) {
9552 for (i = 0;lang[i] != 0;i++)
9553 if (toupper(lang[i]) != toupper(theLang[i]))
9554 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009555 if ((theLang[i] == 0) || (theLang[i] == '-'))
9556 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009557 }
9558not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009559 if (theLang != NULL)
9560 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009561
9562 xmlXPathReleaseObject(ctxt->context, val);
9563 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009564}
9565
9566/**
9567 * xmlXPathNumberFunction:
9568 * @ctxt: the XPath Parser context
9569 * @nargs: the number of arguments
9570 *
9571 * Implement the number() XPath function
9572 * number number(object?)
9573 */
9574void
9575xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9576 xmlXPathObjectPtr cur;
9577 double res;
9578
Daniel Veillarda82b1822004-11-08 16:24:57 +00009579 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009580 if (nargs == 0) {
9581 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009582 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009583 } else {
9584 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9585
9586 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009587 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009588 xmlFree(content);
9589 }
9590 return;
9591 }
9592
9593 CHECK_ARITY(1);
9594 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009595 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009596}
9597
9598/**
9599 * xmlXPathSumFunction:
9600 * @ctxt: the XPath Parser context
9601 * @nargs: the number of arguments
9602 *
9603 * Implement the sum() XPath function
9604 * number sum(node-set)
9605 * The sum function returns the sum of the values of the nodes in
9606 * the argument node-set.
9607 */
9608void
9609xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9610 xmlXPathObjectPtr cur;
9611 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009612 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009613
9614 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009615 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009616 ((ctxt->value->type != XPATH_NODESET) &&
9617 (ctxt->value->type != XPATH_XSLT_TREE)))
9618 XP_ERROR(XPATH_INVALID_TYPE);
9619 cur = valuePop(ctxt);
9620
William M. Brack08171912003-12-29 02:52:11 +00009621 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009622 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9623 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009624 }
9625 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009626 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9627 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009628}
9629
William M. Brack3d426662005-04-19 14:40:28 +00009630/*
9631 * To assure working code on multiple platforms, we want to only depend
9632 * upon the characteristic truncation of converting a floating point value
9633 * to an integer. Unfortunately, because of the different storage sizes
9634 * of our internal floating point value (double) and integer (int), we
9635 * can't directly convert (see bug 301162). This macro is a messy
9636 * 'workaround'
9637 */
9638#define XTRUNC(f, v) \
9639 f = fmod((v), INT_MAX); \
9640 f = (v) - (f) + (double)((int)(f));
9641
Owen Taylor3473f882001-02-23 17:55:21 +00009642/**
9643 * xmlXPathFloorFunction:
9644 * @ctxt: the XPath Parser context
9645 * @nargs: the number of arguments
9646 *
9647 * Implement the floor() XPath function
9648 * number floor(number)
9649 * The floor function returns the largest (closest to positive infinity)
9650 * number that is not greater than the argument and that is an integer.
9651 */
9652void
9653xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009654 double f;
9655
Owen Taylor3473f882001-02-23 17:55:21 +00009656 CHECK_ARITY(1);
9657 CAST_TO_NUMBER;
9658 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009659
William M. Brack3d426662005-04-19 14:40:28 +00009660 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009661 if (f != ctxt->value->floatval) {
9662 if (ctxt->value->floatval > 0)
9663 ctxt->value->floatval = f;
9664 else
9665 ctxt->value->floatval = f - 1;
9666 }
Owen Taylor3473f882001-02-23 17:55:21 +00009667}
9668
9669/**
9670 * xmlXPathCeilingFunction:
9671 * @ctxt: the XPath Parser context
9672 * @nargs: the number of arguments
9673 *
9674 * Implement the ceiling() XPath function
9675 * number ceiling(number)
9676 * The ceiling function returns the smallest (closest to negative infinity)
9677 * number that is not less than the argument and that is an integer.
9678 */
9679void
9680xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9681 double f;
9682
9683 CHECK_ARITY(1);
9684 CAST_TO_NUMBER;
9685 CHECK_TYPE(XPATH_NUMBER);
9686
9687#if 0
9688 ctxt->value->floatval = ceil(ctxt->value->floatval);
9689#else
William M. Brack3d426662005-04-19 14:40:28 +00009690 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009691 if (f != ctxt->value->floatval) {
9692 if (ctxt->value->floatval > 0)
9693 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009694 else {
9695 if (ctxt->value->floatval < 0 && f == 0)
9696 ctxt->value->floatval = xmlXPathNZERO;
9697 else
9698 ctxt->value->floatval = f;
9699 }
9700
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009701 }
Owen Taylor3473f882001-02-23 17:55:21 +00009702#endif
9703}
9704
9705/**
9706 * xmlXPathRoundFunction:
9707 * @ctxt: the XPath Parser context
9708 * @nargs: the number of arguments
9709 *
9710 * Implement the round() XPath function
9711 * number round(number)
9712 * The round function returns the number that is closest to the
9713 * argument and that is an integer. If there are two such numbers,
9714 * then the one that is even is returned.
9715 */
9716void
9717xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9718 double f;
9719
9720 CHECK_ARITY(1);
9721 CAST_TO_NUMBER;
9722 CHECK_TYPE(XPATH_NUMBER);
9723
Daniel Veillardcda96922001-08-21 10:56:31 +00009724 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9725 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9726 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009727 (ctxt->value->floatval == 0.0))
9728 return;
9729
William M. Brack3d426662005-04-19 14:40:28 +00009730 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009731 if (ctxt->value->floatval < 0) {
9732 if (ctxt->value->floatval < f - 0.5)
9733 ctxt->value->floatval = f - 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009734 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009735 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009736 if (ctxt->value->floatval == 0)
9737 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009738 } else {
9739 if (ctxt->value->floatval < f + 0.5)
9740 ctxt->value->floatval = f;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009741 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009742 ctxt->value->floatval = f + 1;
9743 }
Owen Taylor3473f882001-02-23 17:55:21 +00009744}
9745
9746/************************************************************************
9747 * *
9748 * The Parser *
9749 * *
9750 ************************************************************************/
9751
9752/*
William M. Brack08171912003-12-29 02:52:11 +00009753 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009754 * implementation.
9755 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009756static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009757static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009758static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009759static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009760static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9761 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009762
9763/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009764 * xmlXPathCurrentChar:
9765 * @ctxt: the XPath parser context
9766 * @cur: pointer to the beginning of the char
9767 * @len: pointer to the length of the char read
9768 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009769 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009770 * bytes in the input buffer.
9771 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009772 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009773 */
9774
9775static int
9776xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9777 unsigned char c;
9778 unsigned int val;
9779 const xmlChar *cur;
9780
9781 if (ctxt == NULL)
9782 return(0);
9783 cur = ctxt->cur;
9784
9785 /*
9786 * We are supposed to handle UTF8, check it's valid
9787 * From rfc2044: encoding of the Unicode values on UTF-8:
9788 *
9789 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9790 * 0000 0000-0000 007F 0xxxxxxx
9791 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009792 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009793 *
9794 * Check for the 0x110000 limit too
9795 */
9796 c = *cur;
9797 if (c & 0x80) {
9798 if ((cur[1] & 0xc0) != 0x80)
9799 goto encoding_error;
9800 if ((c & 0xe0) == 0xe0) {
9801
9802 if ((cur[2] & 0xc0) != 0x80)
9803 goto encoding_error;
9804 if ((c & 0xf0) == 0xf0) {
9805 if (((c & 0xf8) != 0xf0) ||
9806 ((cur[3] & 0xc0) != 0x80))
9807 goto encoding_error;
9808 /* 4-byte code */
9809 *len = 4;
9810 val = (cur[0] & 0x7) << 18;
9811 val |= (cur[1] & 0x3f) << 12;
9812 val |= (cur[2] & 0x3f) << 6;
9813 val |= cur[3] & 0x3f;
9814 } else {
9815 /* 3-byte code */
9816 *len = 3;
9817 val = (cur[0] & 0xf) << 12;
9818 val |= (cur[1] & 0x3f) << 6;
9819 val |= cur[2] & 0x3f;
9820 }
9821 } else {
9822 /* 2-byte code */
9823 *len = 2;
9824 val = (cur[0] & 0x1f) << 6;
9825 val |= cur[1] & 0x3f;
9826 }
9827 if (!IS_CHAR(val)) {
9828 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009829 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009830 return(val);
9831 } else {
9832 /* 1-byte code */
9833 *len = 1;
9834 return((int) *cur);
9835 }
9836encoding_error:
9837 /*
William M. Brack08171912003-12-29 02:52:11 +00009838 * If we detect an UTF8 error that probably means that the
9839 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009840 * declaration header. Report the error and switch the encoding
9841 * to ISO-Latin-1 (if you don't like this policy, just declare the
9842 * encoding !)
9843 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009844 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009845 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009846}
9847
9848/**
Owen Taylor3473f882001-02-23 17:55:21 +00009849 * xmlXPathParseNCName:
9850 * @ctxt: the XPath Parser context
9851 *
9852 * parse an XML namespace non qualified name.
9853 *
9854 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9855 *
9856 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9857 * CombiningChar | Extender
9858 *
9859 * Returns the namespace name or NULL
9860 */
9861
9862xmlChar *
9863xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009864 const xmlChar *in;
9865 xmlChar *ret;
9866 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009867
Daniel Veillarda82b1822004-11-08 16:24:57 +00009868 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009869 /*
9870 * Accelerator for simple ASCII names
9871 */
9872 in = ctxt->cur;
9873 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9874 ((*in >= 0x41) && (*in <= 0x5A)) ||
9875 (*in == '_')) {
9876 in++;
9877 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9878 ((*in >= 0x41) && (*in <= 0x5A)) ||
9879 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009880 (*in == '_') || (*in == '.') ||
9881 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009882 in++;
9883 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9884 (*in == '[') || (*in == ']') || (*in == ':') ||
9885 (*in == '@') || (*in == '*')) {
9886 count = in - ctxt->cur;
9887 if (count == 0)
9888 return(NULL);
9889 ret = xmlStrndup(ctxt->cur, count);
9890 ctxt->cur = in;
9891 return(ret);
9892 }
9893 }
9894 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009895}
9896
Daniel Veillard2156a562001-04-28 12:24:34 +00009897
Owen Taylor3473f882001-02-23 17:55:21 +00009898/**
9899 * xmlXPathParseQName:
9900 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009901 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009902 *
9903 * parse an XML qualified name
9904 *
9905 * [NS 5] QName ::= (Prefix ':')? LocalPart
9906 *
9907 * [NS 6] Prefix ::= NCName
9908 *
9909 * [NS 7] LocalPart ::= NCName
9910 *
9911 * Returns the function returns the local part, and prefix is updated
9912 * to get the Prefix if any.
9913 */
9914
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009915static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009916xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9917 xmlChar *ret = NULL;
9918
9919 *prefix = NULL;
9920 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009921 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009922 *prefix = ret;
9923 NEXT;
9924 ret = xmlXPathParseNCName(ctxt);
9925 }
9926 return(ret);
9927}
9928
9929/**
9930 * xmlXPathParseName:
9931 * @ctxt: the XPath Parser context
9932 *
9933 * parse an XML name
9934 *
9935 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9936 * CombiningChar | Extender
9937 *
9938 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9939 *
9940 * Returns the namespace name or NULL
9941 */
9942
9943xmlChar *
9944xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009945 const xmlChar *in;
9946 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009947 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009948
Daniel Veillarda82b1822004-11-08 16:24:57 +00009949 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009950 /*
9951 * Accelerator for simple ASCII names
9952 */
9953 in = ctxt->cur;
9954 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9955 ((*in >= 0x41) && (*in <= 0x5A)) ||
9956 (*in == '_') || (*in == ':')) {
9957 in++;
9958 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9959 ((*in >= 0x41) && (*in <= 0x5A)) ||
9960 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009961 (*in == '_') || (*in == '-') ||
9962 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009963 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009964 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009965 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009966 if (count > XML_MAX_NAME_LENGTH) {
9967 ctxt->cur = in;
9968 XP_ERRORNULL(XPATH_EXPR_ERROR);
9969 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009970 ret = xmlStrndup(ctxt->cur, count);
9971 ctxt->cur = in;
9972 return(ret);
9973 }
9974 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009975 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009976}
9977
Daniel Veillard61d80a22001-04-27 17:13:01 +00009978static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009979xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009980 xmlChar buf[XML_MAX_NAMELEN + 5];
9981 int len = 0, l;
9982 int c;
9983
9984 /*
9985 * Handler for more complex cases
9986 */
9987 c = CUR_CHAR(l);
9988 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009989 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9990 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009991 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009992 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009993 return(NULL);
9994 }
9995
9996 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9997 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9998 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009999 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +000010000 (IS_COMBINING(c)) ||
10001 (IS_EXTENDER(c)))) {
10002 COPY_BUF(l,buf,len,c);
10003 NEXTL(l);
10004 c = CUR_CHAR(l);
10005 if (len >= XML_MAX_NAMELEN) {
10006 /*
10007 * Okay someone managed to make a huge name, so he's ready to pay
10008 * for the processing speed.
10009 */
10010 xmlChar *buffer;
10011 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010012
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010013 if (len > XML_MAX_NAME_LENGTH) {
10014 XP_ERRORNULL(XPATH_EXPR_ERROR);
10015 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +000010016 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010017 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010018 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010019 }
10020 memcpy(buffer, buf, len);
10021 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10022 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010023 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +000010024 (IS_COMBINING(c)) ||
10025 (IS_EXTENDER(c))) {
10026 if (len + 10 > max) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010027 if (max > XML_MAX_NAME_LENGTH) {
10028 XP_ERRORNULL(XPATH_EXPR_ERROR);
10029 }
Daniel Veillard61d80a22001-04-27 17:13:01 +000010030 max *= 2;
10031 buffer = (xmlChar *) xmlRealloc(buffer,
10032 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010033 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010034 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010035 }
10036 }
10037 COPY_BUF(l,buffer,len,c);
10038 NEXTL(l);
10039 c = CUR_CHAR(l);
10040 }
10041 buffer[len] = 0;
10042 return(buffer);
10043 }
10044 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010045 if (len == 0)
10046 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010047 return(xmlStrndup(buf, len));
10048}
Daniel Veillard3cd72402002-05-13 10:33:30 +000010049
10050#define MAX_FRAC 20
10051
William M. Brack372a4452004-02-17 13:09:23 +000010052/*
10053 * These are used as divisors for the fractional part of a number.
10054 * Since the table includes 1.0 (representing '0' fractional digits),
10055 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10056 */
10057static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010058 1.0, 10.0, 100.0, 1000.0, 10000.0,
10059 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10060 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10061 100000000000000.0,
10062 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +000010063 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +000010064};
10065
Owen Taylor3473f882001-02-23 17:55:21 +000010066/**
10067 * xmlXPathStringEvalNumber:
10068 * @str: A string to scan
10069 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000010070 * [30a] Float ::= Number ('e' Digits?)?
10071 *
Owen Taylor3473f882001-02-23 17:55:21 +000010072 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010073 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010074 * [31] Digits ::= [0-9]+
10075 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010076 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +000010077 * In complement of the Number expression, this function also handles
10078 * negative values : '-' Number.
10079 *
10080 * Returns the double value.
10081 */
10082double
10083xmlXPathStringEvalNumber(const xmlChar *str) {
10084 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +000010085 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010086 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010087 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010088 int exponent = 0;
10089 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010090#ifdef __GNUC__
10091 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010092 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010093#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010094 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +000010095 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010096 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10097 return(xmlXPathNAN);
10098 }
10099 if (*cur == '-') {
10100 isneg = 1;
10101 cur++;
10102 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010103
10104#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010105 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010106 * tmp/temp is a workaround against a gcc compiler bug
10107 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010108 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010109 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010110 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010111 ret = ret * 10;
10112 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010113 ok = 1;
10114 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010115 temp = (double) tmp;
10116 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010117 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010118#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010119 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010120 while ((*cur >= '0') && (*cur <= '9')) {
10121 ret = ret * 10 + (*cur - '0');
10122 ok = 1;
10123 cur++;
10124 }
10125#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010126
Owen Taylor3473f882001-02-23 17:55:21 +000010127 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010128 int v, frac = 0;
10129 double fraction = 0;
10130
Owen Taylor3473f882001-02-23 17:55:21 +000010131 cur++;
10132 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10133 return(xmlXPathNAN);
10134 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010135 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10136 v = (*cur - '0');
10137 fraction = fraction * 10 + v;
10138 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010139 cur++;
10140 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010141 fraction /= my_pow10[frac];
10142 ret = ret + fraction;
10143 while ((*cur >= '0') && (*cur <= '9'))
10144 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010145 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010146 if ((*cur == 'e') || (*cur == 'E')) {
10147 cur++;
10148 if (*cur == '-') {
10149 is_exponent_negative = 1;
10150 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010151 } else if (*cur == '+') {
10152 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010153 }
10154 while ((*cur >= '0') && (*cur <= '9')) {
10155 exponent = exponent * 10 + (*cur - '0');
10156 cur++;
10157 }
10158 }
William M. Brack76e95df2003-10-18 16:20:14 +000010159 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010160 if (*cur != 0) return(xmlXPathNAN);
10161 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010162 if (is_exponent_negative) exponent = -exponent;
10163 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010164 return(ret);
10165}
10166
10167/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010168 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010169 * @ctxt: the XPath Parser context
10170 *
10171 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010172 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010173 * [31] Digits ::= [0-9]+
10174 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010175 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010176 *
10177 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010178static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010179xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10180{
Owen Taylor3473f882001-02-23 17:55:21 +000010181 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010182 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010183 int exponent = 0;
10184 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010185#ifdef __GNUC__
10186 unsigned long tmp = 0;
10187 double temp;
10188#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010189
10190 CHECK_ERROR;
10191 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10192 XP_ERROR(XPATH_NUMBER_ERROR);
10193 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010194#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010195 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010196 * tmp/temp is a workaround against a gcc compiler bug
10197 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010198 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010199 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010200 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010201 ret = ret * 10;
10202 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010203 ok = 1;
10204 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010205 temp = (double) tmp;
10206 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010207 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010208#else
10209 ret = 0;
10210 while ((CUR >= '0') && (CUR <= '9')) {
10211 ret = ret * 10 + (CUR - '0');
10212 ok = 1;
10213 NEXT;
10214 }
10215#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010216 if (CUR == '.') {
Phil Shaferee32ad32010-11-03 20:53:55 +010010217 int v, frac = 0;
10218 double fraction = 0;
10219
Owen Taylor3473f882001-02-23 17:55:21 +000010220 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010221 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10222 XP_ERROR(XPATH_NUMBER_ERROR);
10223 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010224 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10225 v = (CUR - '0');
10226 fraction = fraction * 10 + v;
10227 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010228 NEXT;
10229 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010230 fraction /= my_pow10[frac];
10231 ret = ret + fraction;
10232 while ((CUR >= '0') && (CUR <= '9'))
10233 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010234 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010235 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010236 NEXT;
10237 if (CUR == '-') {
10238 is_exponent_negative = 1;
10239 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010240 } else if (CUR == '+') {
10241 NEXT;
10242 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010243 while ((CUR >= '0') && (CUR <= '9')) {
10244 exponent = exponent * 10 + (CUR - '0');
10245 NEXT;
10246 }
10247 if (is_exponent_negative)
10248 exponent = -exponent;
10249 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010250 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010251 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010252 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010253}
10254
10255/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010256 * xmlXPathParseLiteral:
10257 * @ctxt: the XPath Parser context
10258 *
10259 * Parse a Literal
10260 *
10261 * [29] Literal ::= '"' [^"]* '"'
10262 * | "'" [^']* "'"
10263 *
10264 * Returns the value found or NULL in case of error
10265 */
10266static xmlChar *
10267xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10268 const xmlChar *q;
10269 xmlChar *ret = NULL;
10270
10271 if (CUR == '"') {
10272 NEXT;
10273 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010274 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010275 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010276 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010277 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010278 } else {
10279 ret = xmlStrndup(q, CUR_PTR - q);
10280 NEXT;
10281 }
10282 } else if (CUR == '\'') {
10283 NEXT;
10284 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010285 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010286 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010287 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010288 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010289 } else {
10290 ret = xmlStrndup(q, CUR_PTR - q);
10291 NEXT;
10292 }
10293 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010294 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010295 }
10296 return(ret);
10297}
10298
10299/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010300 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010301 * @ctxt: the XPath Parser context
10302 *
10303 * Parse a Literal and push it on the stack.
10304 *
10305 * [29] Literal ::= '"' [^"]* '"'
10306 * | "'" [^']* "'"
10307 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010308 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010309 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010310static void
10311xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010312 const xmlChar *q;
10313 xmlChar *ret = NULL;
10314
10315 if (CUR == '"') {
10316 NEXT;
10317 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010318 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010319 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010320 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010321 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10322 } else {
10323 ret = xmlStrndup(q, CUR_PTR - q);
10324 NEXT;
10325 }
10326 } else if (CUR == '\'') {
10327 NEXT;
10328 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010329 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010330 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010331 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010332 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10333 } else {
10334 ret = xmlStrndup(q, CUR_PTR - q);
10335 NEXT;
10336 }
10337 } else {
10338 XP_ERROR(XPATH_START_LITERAL_ERROR);
10339 }
10340 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010341 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010342 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010343 xmlFree(ret);
10344}
10345
10346/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010347 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010348 * @ctxt: the XPath Parser context
10349 *
10350 * Parse a VariableReference, evaluate it and push it on the stack.
10351 *
10352 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010353 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010354 * of any of the types that are possible for the value of an expression,
10355 * and may also be of additional types not specified here.
10356 *
10357 * Early evaluation is possible since:
10358 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010359 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010360 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010361 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010362 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010363static void
10364xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010365 xmlChar *name;
10366 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010367
10368 SKIP_BLANKS;
10369 if (CUR != '$') {
10370 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10371 }
10372 NEXT;
10373 name = xmlXPathParseQName(ctxt, &prefix);
10374 if (name == NULL) {
10375 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10376 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010377 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010378 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10379 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010380 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010381 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
Daniel Veillard47881282012-09-07 14:24:50 +080010382 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
Daniel Veillardb3d14912005-09-04 20:47:39 +000010383 }
Owen Taylor3473f882001-02-23 17:55:21 +000010384}
10385
10386/**
10387 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010388 * @name: a name string
10389 *
10390 * Is the name given a NodeType one.
10391 *
10392 * [38] NodeType ::= 'comment'
10393 * | 'text'
10394 * | 'processing-instruction'
10395 * | 'node'
10396 *
10397 * Returns 1 if true 0 otherwise
10398 */
10399int
10400xmlXPathIsNodeType(const xmlChar *name) {
10401 if (name == NULL)
10402 return(0);
10403
Daniel Veillard1971ee22002-01-31 20:29:19 +000010404 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010405 return(1);
10406 if (xmlStrEqual(name, BAD_CAST "text"))
10407 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010408 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010409 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010410 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010411 return(1);
10412 return(0);
10413}
10414
10415/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010416 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010417 * @ctxt: the XPath Parser context
10418 *
10419 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010420 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010421 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010422 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010423 * pushed on the stack
10424 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010425static void
10426xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010427 xmlChar *name;
10428 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010429 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010430 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010431
10432 name = xmlXPathParseQName(ctxt, &prefix);
10433 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010434 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010435 XP_ERROR(XPATH_EXPR_ERROR);
10436 }
10437 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010438#ifdef DEBUG_EXPR
10439 if (prefix == NULL)
10440 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10441 name);
10442 else
10443 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10444 prefix, name);
10445#endif
10446
Owen Taylor3473f882001-02-23 17:55:21 +000010447 if (CUR != '(') {
10448 XP_ERROR(XPATH_EXPR_ERROR);
10449 }
10450 NEXT;
10451 SKIP_BLANKS;
10452
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010453 /*
10454 * Optimization for count(): we don't need the node-set to be sorted.
10455 */
10456 if ((prefix == NULL) && (name[0] == 'c') &&
10457 xmlStrEqual(name, BAD_CAST "count"))
10458 {
10459 sort = 0;
10460 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010461 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010462 if (CUR != ')') {
10463 while (CUR != 0) {
10464 int op1 = ctxt->comp->last;
10465 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010466 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010467 if (ctxt->error != XPATH_EXPRESSION_OK) {
10468 xmlFree(name);
10469 xmlFree(prefix);
10470 return;
10471 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010472 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10473 nbargs++;
10474 if (CUR == ')') break;
10475 if (CUR != ',') {
10476 XP_ERROR(XPATH_EXPR_ERROR);
10477 }
10478 NEXT;
10479 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010480 }
Owen Taylor3473f882001-02-23 17:55:21 +000010481 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010482 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10483 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010484 NEXT;
10485 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010486}
10487
10488/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010489 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010490 * @ctxt: the XPath Parser context
10491 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010492 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010493 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010494 * | Literal
10495 * | Number
10496 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010497 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010498 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010499 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010500static void
10501xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010502 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010503 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010504 else if (CUR == '(') {
10505 NEXT;
10506 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010507 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010508 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010509 if (CUR != ')') {
10510 XP_ERROR(XPATH_EXPR_ERROR);
10511 }
10512 NEXT;
10513 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010514 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010515 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010516 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010517 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010518 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010519 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010520 }
10521 SKIP_BLANKS;
10522}
10523
10524/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010525 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010526 * @ctxt: the XPath Parser context
10527 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010528 * [20] FilterExpr ::= PrimaryExpr
10529 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010530 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010531 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010532 * Square brackets are used to filter expressions in the same way that
10533 * they are used in location paths. It is an error if the expression to
10534 * be filtered does not evaluate to a node-set. The context node list
10535 * used for evaluating the expression in square brackets is the node-set
10536 * to be filtered listed in document order.
10537 */
10538
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010539static void
10540xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10541 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010542 CHECK_ERROR;
10543 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010544
Owen Taylor3473f882001-02-23 17:55:21 +000010545 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010546 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010547 SKIP_BLANKS;
10548 }
10549
Daniel Veillard45490ae2008-07-29 09:13:19 +000010550
Owen Taylor3473f882001-02-23 17:55:21 +000010551}
10552
10553/**
10554 * xmlXPathScanName:
10555 * @ctxt: the XPath Parser context
10556 *
10557 * Trickery: parse an XML name but without consuming the input flow
10558 * Needed to avoid insanity in the parser state.
10559 *
10560 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10561 * CombiningChar | Extender
10562 *
10563 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10564 *
10565 * [6] Names ::= Name (S Name)*
10566 *
10567 * Returns the Name parsed or NULL
10568 */
10569
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010570static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010571xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010572 int len = 0, l;
10573 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010574 const xmlChar *cur;
10575 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010576
Daniel Veillard03226812004-11-01 14:55:21 +000010577 cur = ctxt->cur;
10578
10579 c = CUR_CHAR(l);
10580 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10581 (!IS_LETTER(c) && (c != '_') &&
10582 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010583 return(NULL);
10584 }
10585
Daniel Veillard03226812004-11-01 14:55:21 +000010586 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10587 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10588 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010589 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010590 (IS_COMBINING(c)) ||
10591 (IS_EXTENDER(c)))) {
10592 len += l;
10593 NEXTL(l);
10594 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010595 }
Daniel Veillard03226812004-11-01 14:55:21 +000010596 ret = xmlStrndup(cur, ctxt->cur - cur);
10597 ctxt->cur = cur;
10598 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010599}
10600
10601/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010602 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010603 * @ctxt: the XPath Parser context
10604 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010605 * [19] PathExpr ::= LocationPath
10606 * | FilterExpr
10607 * | FilterExpr '/' RelativeLocationPath
10608 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010609 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010610 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010611 * The / operator and // operators combine an arbitrary expression
10612 * and a relative location path. It is an error if the expression
10613 * does not evaluate to a node-set.
10614 * The / operator does composition in the same way as when / is
10615 * used in a location path. As in location paths, // is short for
10616 * /descendant-or-self::node()/.
10617 */
10618
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010619static void
10620xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010621 int lc = 1; /* Should we branch to LocationPath ? */
10622 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10623
10624 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010625 if ((CUR == '$') || (CUR == '(') ||
10626 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010627 (CUR == '\'') || (CUR == '"') ||
10628 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010629 lc = 0;
10630 } else if (CUR == '*') {
10631 /* relative or absolute location path */
10632 lc = 1;
10633 } else if (CUR == '/') {
10634 /* relative or absolute location path */
10635 lc = 1;
10636 } else if (CUR == '@') {
10637 /* relative abbreviated attribute location path */
10638 lc = 1;
10639 } else if (CUR == '.') {
10640 /* relative abbreviated attribute location path */
10641 lc = 1;
10642 } else {
10643 /*
10644 * Problem is finding if we have a name here whether it's:
10645 * - a nodetype
10646 * - a function call in which case it's followed by '('
10647 * - an axis in which case it's followed by ':'
10648 * - a element name
10649 * We do an a priori analysis here rather than having to
10650 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010651 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010652 * read/write/debug.
10653 */
10654 SKIP_BLANKS;
10655 name = xmlXPathScanName(ctxt);
10656 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10657#ifdef DEBUG_STEP
10658 xmlGenericError(xmlGenericErrorContext,
10659 "PathExpr: Axis\n");
10660#endif
10661 lc = 1;
10662 xmlFree(name);
10663 } else if (name != NULL) {
10664 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010665
Daniel Veillard45490ae2008-07-29 09:13:19 +000010666
Owen Taylor3473f882001-02-23 17:55:21 +000010667 while (NXT(len) != 0) {
10668 if (NXT(len) == '/') {
10669 /* element name */
10670#ifdef DEBUG_STEP
10671 xmlGenericError(xmlGenericErrorContext,
10672 "PathExpr: AbbrRelLocation\n");
10673#endif
10674 lc = 1;
10675 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010676 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010677 /* ignore blanks */
10678 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010679 } else if (NXT(len) == ':') {
10680#ifdef DEBUG_STEP
10681 xmlGenericError(xmlGenericErrorContext,
10682 "PathExpr: AbbrRelLocation\n");
10683#endif
10684 lc = 1;
10685 break;
10686 } else if ((NXT(len) == '(')) {
10687 /* Note Type or Function */
10688 if (xmlXPathIsNodeType(name)) {
10689#ifdef DEBUG_STEP
10690 xmlGenericError(xmlGenericErrorContext,
10691 "PathExpr: Type search\n");
10692#endif
10693 lc = 1;
10694 } else {
10695#ifdef DEBUG_STEP
10696 xmlGenericError(xmlGenericErrorContext,
10697 "PathExpr: function call\n");
10698#endif
10699 lc = 0;
10700 }
10701 break;
10702 } else if ((NXT(len) == '[')) {
10703 /* element name */
10704#ifdef DEBUG_STEP
10705 xmlGenericError(xmlGenericErrorContext,
10706 "PathExpr: AbbrRelLocation\n");
10707#endif
10708 lc = 1;
10709 break;
10710 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10711 (NXT(len) == '=')) {
10712 lc = 1;
10713 break;
10714 } else {
10715 lc = 1;
10716 break;
10717 }
10718 len++;
10719 }
10720 if (NXT(len) == 0) {
10721#ifdef DEBUG_STEP
10722 xmlGenericError(xmlGenericErrorContext,
10723 "PathExpr: AbbrRelLocation\n");
10724#endif
10725 /* element name */
10726 lc = 1;
10727 }
10728 xmlFree(name);
10729 } else {
William M. Brack08171912003-12-29 02:52:11 +000010730 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010731 XP_ERROR(XPATH_EXPR_ERROR);
10732 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010733 }
Owen Taylor3473f882001-02-23 17:55:21 +000010734
10735 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010736 if (CUR == '/') {
10737 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10738 } else {
10739 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010740 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010741 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010742 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010743 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010744 CHECK_ERROR;
10745 if ((CUR == '/') && (NXT(1) == '/')) {
10746 SKIP(2);
10747 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010748
10749 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10750 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10751 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10752
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010753 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010754 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010755 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010756 }
10757 }
10758 SKIP_BLANKS;
10759}
10760
10761/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010762 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010763 * @ctxt: the XPath Parser context
10764 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010765 * [18] UnionExpr ::= PathExpr
10766 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010767 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010768 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010769 */
10770
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010771static void
10772xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10773 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010774 CHECK_ERROR;
10775 SKIP_BLANKS;
10776 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010777 int op1 = ctxt->comp->last;
10778 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010779
10780 NEXT;
10781 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010782 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010783
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010784 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10785
Owen Taylor3473f882001-02-23 17:55:21 +000010786 SKIP_BLANKS;
10787 }
Owen Taylor3473f882001-02-23 17:55:21 +000010788}
10789
10790/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010791 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010792 * @ctxt: the XPath Parser context
10793 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010794 * [27] UnaryExpr ::= UnionExpr
10795 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010796 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010797 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010798 */
10799
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010800static void
10801xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010802 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010803 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010804
10805 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010806 while (CUR == '-') {
10807 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010808 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010809 NEXT;
10810 SKIP_BLANKS;
10811 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010812
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010813 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010814 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010815 if (found) {
10816 if (minus)
10817 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10818 else
10819 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010820 }
10821}
10822
10823/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010824 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010825 * @ctxt: the XPath Parser context
10826 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010827 * [26] MultiplicativeExpr ::= UnaryExpr
10828 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10829 * | MultiplicativeExpr 'div' UnaryExpr
10830 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010831 * [34] MultiplyOperator ::= '*'
10832 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010833 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010834 */
10835
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010836static void
10837xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10838 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010839 CHECK_ERROR;
10840 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010841 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010842 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10843 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10844 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010845 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010846
10847 if (CUR == '*') {
10848 op = 0;
10849 NEXT;
10850 } else if (CUR == 'd') {
10851 op = 1;
10852 SKIP(3);
10853 } else if (CUR == 'm') {
10854 op = 2;
10855 SKIP(3);
10856 }
10857 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010858 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010859 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010860 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010861 SKIP_BLANKS;
10862 }
10863}
10864
10865/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010866 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010867 * @ctxt: the XPath Parser context
10868 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010869 * [25] AdditiveExpr ::= MultiplicativeExpr
10870 * | AdditiveExpr '+' MultiplicativeExpr
10871 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010872 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010873 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010874 */
10875
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010876static void
10877xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010878
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010879 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010880 CHECK_ERROR;
10881 SKIP_BLANKS;
10882 while ((CUR == '+') || (CUR == '-')) {
10883 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010884 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010885
10886 if (CUR == '+') plus = 1;
10887 else plus = 0;
10888 NEXT;
10889 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010890 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010891 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010892 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010893 SKIP_BLANKS;
10894 }
10895}
10896
10897/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010898 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010899 * @ctxt: the XPath Parser context
10900 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010901 * [24] RelationalExpr ::= AdditiveExpr
10902 * | RelationalExpr '<' AdditiveExpr
10903 * | RelationalExpr '>' AdditiveExpr
10904 * | RelationalExpr '<=' AdditiveExpr
10905 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010906 *
10907 * A <= B > C is allowed ? Answer from James, yes with
10908 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10909 * which is basically what got implemented.
10910 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010911 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010912 * on the stack
10913 */
10914
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010915static void
10916xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10917 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010918 CHECK_ERROR;
10919 SKIP_BLANKS;
10920 while ((CUR == '<') ||
10921 (CUR == '>') ||
10922 ((CUR == '<') && (NXT(1) == '=')) ||
10923 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010924 int inf, strict;
10925 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010926
10927 if (CUR == '<') inf = 1;
10928 else inf = 0;
10929 if (NXT(1) == '=') strict = 0;
10930 else strict = 1;
10931 NEXT;
10932 if (!strict) NEXT;
10933 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010934 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010935 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010936 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010937 SKIP_BLANKS;
10938 }
10939}
10940
10941/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010942 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010943 * @ctxt: the XPath Parser context
10944 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010945 * [23] EqualityExpr ::= RelationalExpr
10946 * | EqualityExpr '=' RelationalExpr
10947 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010948 *
10949 * A != B != C is allowed ? Answer from James, yes with
10950 * (RelationalExpr = RelationalExpr) = RelationalExpr
10951 * (RelationalExpr != RelationalExpr) != RelationalExpr
10952 * which is basically what got implemented.
10953 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010954 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010955 *
10956 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010957static void
10958xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10959 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010960 CHECK_ERROR;
10961 SKIP_BLANKS;
10962 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010963 int eq;
10964 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010965
10966 if (CUR == '=') eq = 1;
10967 else eq = 0;
10968 NEXT;
10969 if (!eq) NEXT;
10970 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010971 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010972 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010973 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010974 SKIP_BLANKS;
10975 }
10976}
10977
10978/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010979 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010980 * @ctxt: the XPath Parser context
10981 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010982 * [22] AndExpr ::= EqualityExpr
10983 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010984 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010985 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010986 *
10987 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010988static void
10989xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10990 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010991 CHECK_ERROR;
10992 SKIP_BLANKS;
10993 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010994 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010995 SKIP(3);
10996 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010997 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010998 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010999 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011000 SKIP_BLANKS;
11001 }
11002}
11003
11004/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000011005 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000011006 * @ctxt: the XPath Parser context
11007 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011008 * [14] Expr ::= OrExpr
11009 * [21] OrExpr ::= AndExpr
11010 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000011011 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011012 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000011013 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011014static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011015xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011016 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011017 CHECK_ERROR;
11018 SKIP_BLANKS;
11019 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011020 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011021 SKIP(2);
11022 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011023 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011024 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011025 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011026 SKIP_BLANKS;
11027 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011028 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011029 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011030 /*
11031 * This is the main place to eliminate sorting for
11032 * operations which don't require a sorted node-set.
11033 * E.g. count().
11034 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011035 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11036 }
Owen Taylor3473f882001-02-23 17:55:21 +000011037}
11038
11039/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011040 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000011041 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011042 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000011043 *
11044 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000011045 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000011046 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011047 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000011048 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011049static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011050xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011051 int op1 = ctxt->comp->last;
11052
11053 SKIP_BLANKS;
11054 if (CUR != '[') {
11055 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11056 }
11057 NEXT;
11058 SKIP_BLANKS;
11059
11060 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011061 /*
11062 * This call to xmlXPathCompileExpr() will deactivate sorting
11063 * of the predicate result.
11064 * TODO: Sorting is still activated for filters, since I'm not
11065 * sure if needed. Normally sorting should not be needed, since
11066 * a filter can only diminish the number of items in a sequence,
11067 * but won't change its order; so if the initial sequence is sorted,
11068 * subsequent sorting is not needed.
11069 */
11070 if (! filter)
11071 xmlXPathCompileExpr(ctxt, 0);
11072 else
11073 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011074 CHECK_ERROR;
11075
11076 if (CUR != ']') {
11077 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11078 }
11079
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011080 if (filter)
11081 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11082 else
11083 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011084
11085 NEXT;
11086 SKIP_BLANKS;
11087}
11088
11089/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011090 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011091 * @ctxt: the XPath Parser context
11092 * @test: pointer to a xmlXPathTestVal
11093 * @type: pointer to a xmlXPathTypeVal
11094 * @prefix: placeholder for a possible name prefix
11095 *
11096 * [7] NodeTest ::= NameTest
11097 * | NodeType '(' ')'
11098 * | 'processing-instruction' '(' Literal ')'
11099 *
11100 * [37] NameTest ::= '*'
11101 * | NCName ':' '*'
11102 * | QName
11103 * [38] NodeType ::= 'comment'
11104 * | 'text'
11105 * | 'processing-instruction'
11106 * | 'node'
11107 *
William M. Brack08171912003-12-29 02:52:11 +000011108 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011109 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011110static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011111xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11112 xmlXPathTypeVal *type, const xmlChar **prefix,
11113 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011114 int blanks;
11115
11116 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11117 STRANGE;
11118 return(NULL);
11119 }
William M. Brack78637da2003-07-31 14:47:38 +000011120 *type = (xmlXPathTypeVal) 0;
11121 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011122 *prefix = NULL;
11123 SKIP_BLANKS;
11124
11125 if ((name == NULL) && (CUR == '*')) {
11126 /*
11127 * All elements
11128 */
11129 NEXT;
11130 *test = NODE_TEST_ALL;
11131 return(NULL);
11132 }
11133
11134 if (name == NULL)
11135 name = xmlXPathParseNCName(ctxt);
11136 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011137 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011138 }
11139
William M. Brack76e95df2003-10-18 16:20:14 +000011140 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011141 SKIP_BLANKS;
11142 if (CUR == '(') {
11143 NEXT;
11144 /*
11145 * NodeType or PI search
11146 */
11147 if (xmlStrEqual(name, BAD_CAST "comment"))
11148 *type = NODE_TYPE_COMMENT;
11149 else if (xmlStrEqual(name, BAD_CAST "node"))
11150 *type = NODE_TYPE_NODE;
11151 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11152 *type = NODE_TYPE_PI;
11153 else if (xmlStrEqual(name, BAD_CAST "text"))
11154 *type = NODE_TYPE_TEXT;
11155 else {
11156 if (name != NULL)
11157 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011158 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011159 }
11160
11161 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011162
Owen Taylor3473f882001-02-23 17:55:21 +000011163 SKIP_BLANKS;
11164 if (*type == NODE_TYPE_PI) {
11165 /*
11166 * Specific case: search a PI by name.
11167 */
Owen Taylor3473f882001-02-23 17:55:21 +000011168 if (name != NULL)
11169 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011170 name = NULL;
11171 if (CUR != ')') {
11172 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011173 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011174 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011175 SKIP_BLANKS;
11176 }
Owen Taylor3473f882001-02-23 17:55:21 +000011177 }
11178 if (CUR != ')') {
11179 if (name != NULL)
11180 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011181 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011182 }
11183 NEXT;
11184 return(name);
11185 }
11186 *test = NODE_TEST_NAME;
11187 if ((!blanks) && (CUR == ':')) {
11188 NEXT;
11189
11190 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011191 * Since currently the parser context don't have a
11192 * namespace list associated:
11193 * The namespace name for this prefix can be computed
11194 * only at evaluation time. The compilation is done
11195 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011196 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011197#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011198 *prefix = xmlXPathNsLookup(ctxt->context, name);
11199 if (name != NULL)
11200 xmlFree(name);
11201 if (*prefix == NULL) {
11202 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11203 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011204#else
11205 *prefix = name;
11206#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011207
11208 if (CUR == '*') {
11209 /*
11210 * All elements
11211 */
11212 NEXT;
11213 *test = NODE_TEST_ALL;
11214 return(NULL);
11215 }
11216
11217 name = xmlXPathParseNCName(ctxt);
11218 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011219 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011220 }
11221 }
11222 return(name);
11223}
11224
11225/**
11226 * xmlXPathIsAxisName:
11227 * @name: a preparsed name token
11228 *
11229 * [6] AxisName ::= 'ancestor'
11230 * | 'ancestor-or-self'
11231 * | 'attribute'
11232 * | 'child'
11233 * | 'descendant'
11234 * | 'descendant-or-self'
11235 * | 'following'
11236 * | 'following-sibling'
11237 * | 'namespace'
11238 * | 'parent'
11239 * | 'preceding'
11240 * | 'preceding-sibling'
11241 * | 'self'
11242 *
11243 * Returns the axis or 0
11244 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011245static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011246xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011247 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011248 switch (name[0]) {
11249 case 'a':
11250 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11251 ret = AXIS_ANCESTOR;
11252 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11253 ret = AXIS_ANCESTOR_OR_SELF;
11254 if (xmlStrEqual(name, BAD_CAST "attribute"))
11255 ret = AXIS_ATTRIBUTE;
11256 break;
11257 case 'c':
11258 if (xmlStrEqual(name, BAD_CAST "child"))
11259 ret = AXIS_CHILD;
11260 break;
11261 case 'd':
11262 if (xmlStrEqual(name, BAD_CAST "descendant"))
11263 ret = AXIS_DESCENDANT;
11264 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11265 ret = AXIS_DESCENDANT_OR_SELF;
11266 break;
11267 case 'f':
11268 if (xmlStrEqual(name, BAD_CAST "following"))
11269 ret = AXIS_FOLLOWING;
11270 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11271 ret = AXIS_FOLLOWING_SIBLING;
11272 break;
11273 case 'n':
11274 if (xmlStrEqual(name, BAD_CAST "namespace"))
11275 ret = AXIS_NAMESPACE;
11276 break;
11277 case 'p':
11278 if (xmlStrEqual(name, BAD_CAST "parent"))
11279 ret = AXIS_PARENT;
11280 if (xmlStrEqual(name, BAD_CAST "preceding"))
11281 ret = AXIS_PRECEDING;
11282 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11283 ret = AXIS_PRECEDING_SIBLING;
11284 break;
11285 case 's':
11286 if (xmlStrEqual(name, BAD_CAST "self"))
11287 ret = AXIS_SELF;
11288 break;
11289 }
11290 return(ret);
11291}
11292
11293/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011294 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011295 * @ctxt: the XPath Parser context
11296 *
11297 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011298 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011299 *
11300 * [12] AbbreviatedStep ::= '.' | '..'
11301 *
11302 * [5] AxisSpecifier ::= AxisName '::'
11303 * | AbbreviatedAxisSpecifier
11304 *
11305 * [13] AbbreviatedAxisSpecifier ::= '@'?
11306 *
11307 * Modified for XPtr range support as:
11308 *
11309 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11310 * | AbbreviatedStep
11311 * | 'range-to' '(' Expr ')' Predicate*
11312 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011313 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011314 * A location step of . is short for self::node(). This is
11315 * particularly useful in conjunction with //. For example, the
11316 * location path .//para is short for
11317 * self::node()/descendant-or-self::node()/child::para
11318 * and so will select all para descendant elements of the context
11319 * node.
11320 * Similarly, a location step of .. is short for parent::node().
11321 * For example, ../title is short for parent::node()/child::title
11322 * and so will select the title children of the parent of the context
11323 * node.
11324 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011325static void
11326xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011327#ifdef LIBXML_XPTR_ENABLED
11328 int rangeto = 0;
11329 int op2 = -1;
11330#endif
11331
Owen Taylor3473f882001-02-23 17:55:21 +000011332 SKIP_BLANKS;
11333 if ((CUR == '.') && (NXT(1) == '.')) {
11334 SKIP(2);
11335 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011336 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11337 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011338 } else if (CUR == '.') {
11339 NEXT;
11340 SKIP_BLANKS;
11341 } else {
11342 xmlChar *name = NULL;
11343 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011344 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011345 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011346 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011347 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011348
11349 /*
11350 * The modification needed for XPointer change to the production
11351 */
11352#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011353 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011354 name = xmlXPathParseNCName(ctxt);
11355 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011356 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011357 xmlFree(name);
11358 SKIP_BLANKS;
11359 if (CUR != '(') {
11360 XP_ERROR(XPATH_EXPR_ERROR);
11361 }
11362 NEXT;
11363 SKIP_BLANKS;
11364
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011365 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011366 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011367 CHECK_ERROR;
11368
11369 SKIP_BLANKS;
11370 if (CUR != ')') {
11371 XP_ERROR(XPATH_EXPR_ERROR);
11372 }
11373 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011374 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011375 goto eval_predicates;
11376 }
11377 }
11378#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011379 if (CUR == '*') {
11380 axis = AXIS_CHILD;
11381 } else {
11382 if (name == NULL)
11383 name = xmlXPathParseNCName(ctxt);
11384 if (name != NULL) {
11385 axis = xmlXPathIsAxisName(name);
11386 if (axis != 0) {
11387 SKIP_BLANKS;
11388 if ((CUR == ':') && (NXT(1) == ':')) {
11389 SKIP(2);
11390 xmlFree(name);
11391 name = NULL;
11392 } else {
11393 /* an element name can conflict with an axis one :-\ */
11394 axis = AXIS_CHILD;
11395 }
Owen Taylor3473f882001-02-23 17:55:21 +000011396 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011397 axis = AXIS_CHILD;
11398 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011399 } else if (CUR == '@') {
11400 NEXT;
11401 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011402 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011403 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011404 }
Owen Taylor3473f882001-02-23 17:55:21 +000011405 }
11406
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011407 if (ctxt->error != XPATH_EXPRESSION_OK) {
11408 xmlFree(name);
11409 return;
11410 }
Owen Taylor3473f882001-02-23 17:55:21 +000011411
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011412 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011413 if (test == 0)
11414 return;
11415
Daniel Veillarded6c5492005-07-23 15:00:22 +000011416 if ((prefix != NULL) && (ctxt->context != NULL) &&
11417 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11418 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11419 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11420 }
11421 }
Owen Taylor3473f882001-02-23 17:55:21 +000011422#ifdef DEBUG_STEP
11423 xmlGenericError(xmlGenericErrorContext,
11424 "Basis : computing new set\n");
11425#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011426
Owen Taylor3473f882001-02-23 17:55:21 +000011427#ifdef DEBUG_STEP
11428 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011429 if (ctxt->value == NULL)
11430 xmlGenericError(xmlGenericErrorContext, "no value\n");
11431 else if (ctxt->value->nodesetval == NULL)
11432 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11433 else
11434 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011435#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011436
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011437#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011438eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011439#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011440 op1 = ctxt->comp->last;
11441 ctxt->comp->last = -1;
11442
Owen Taylor3473f882001-02-23 17:55:21 +000011443 SKIP_BLANKS;
11444 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011445 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011446 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011447
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011448#ifdef LIBXML_XPTR_ENABLED
11449 if (rangeto) {
11450 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11451 } else
11452#endif
11453 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11454 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011455
Owen Taylor3473f882001-02-23 17:55:21 +000011456 }
11457#ifdef DEBUG_STEP
11458 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011459 if (ctxt->value == NULL)
11460 xmlGenericError(xmlGenericErrorContext, "no value\n");
11461 else if (ctxt->value->nodesetval == NULL)
11462 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11463 else
11464 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11465 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011466#endif
11467}
11468
11469/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011470 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011471 * @ctxt: the XPath Parser context
11472 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011473 * [3] RelativeLocationPath ::= Step
11474 * | RelativeLocationPath '/' Step
11475 * | AbbreviatedRelativeLocationPath
11476 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011477 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011478 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011479 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011480static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011481xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011482(xmlXPathParserContextPtr ctxt) {
11483 SKIP_BLANKS;
11484 if ((CUR == '/') && (NXT(1) == '/')) {
11485 SKIP(2);
11486 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011487 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11488 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011489 } else if (CUR == '/') {
11490 NEXT;
11491 SKIP_BLANKS;
11492 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011493 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011494 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011495 SKIP_BLANKS;
11496 while (CUR == '/') {
11497 if ((CUR == '/') && (NXT(1) == '/')) {
11498 SKIP(2);
11499 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011500 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011501 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011502 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011503 } else if (CUR == '/') {
11504 NEXT;
11505 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011506 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011507 }
11508 SKIP_BLANKS;
11509 }
11510}
11511
11512/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011513 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011514 * @ctxt: the XPath Parser context
11515 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011516 * [1] LocationPath ::= RelativeLocationPath
11517 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011518 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011519 * | AbbreviatedAbsoluteLocationPath
11520 * [10] AbbreviatedAbsoluteLocationPath ::=
11521 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011522 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011523 * Compile a location path
11524 *
Owen Taylor3473f882001-02-23 17:55:21 +000011525 * // is short for /descendant-or-self::node()/. For example,
11526 * //para is short for /descendant-or-self::node()/child::para and
11527 * so will select any para element in the document (even a para element
11528 * that is a document element will be selected by //para since the
11529 * document element node is a child of the root node); div//para is
11530 * short for div/descendant-or-self::node()/child::para and so will
11531 * select all para descendants of div children.
11532 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011533static void
11534xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011535 SKIP_BLANKS;
11536 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011537 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011538 } else {
11539 while (CUR == '/') {
11540 if ((CUR == '/') && (NXT(1) == '/')) {
11541 SKIP(2);
11542 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011543 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11544 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011545 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011546 } else if (CUR == '/') {
11547 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011548 SKIP_BLANKS;
11549 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011550 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011551 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011552 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011553 }
Martin729601f2009-10-12 22:42:26 +020011554 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011555 }
11556 }
11557}
11558
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011559/************************************************************************
11560 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011561 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011562 * *
11563 ************************************************************************/
11564
Daniel Veillardf06307e2001-07-03 10:35:50 +000011565static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011566xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11567
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011568#ifdef DEBUG_STEP
11569static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011570xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011571 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011572{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011573 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011574 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011575 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011576 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011577 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011578 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011579 xmlGenericError(xmlGenericErrorContext,
11580 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011581 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011582 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011583 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011584 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011585 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011586 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011587 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011588 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011589 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011590 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011591 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011592 xmlGenericError(xmlGenericErrorContext,
11593 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011594 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011595 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011596 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011597 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011598 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011599 xmlGenericError(xmlGenericErrorContext,
11600 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011601 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011602 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011603 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011604 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011605 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011606 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011607 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011608 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011609 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011610 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011611 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011612 xmlGenericError(xmlGenericErrorContext,
11613 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011614 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011615 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011616 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011617 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011618 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011619 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011620 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011621 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011622 case NODE_TEST_NONE:
11623 xmlGenericError(xmlGenericErrorContext,
11624 " searching for none !!!\n");
11625 break;
11626 case NODE_TEST_TYPE:
11627 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011628 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011629 break;
11630 case NODE_TEST_PI:
11631 xmlGenericError(xmlGenericErrorContext,
11632 " searching for PI !!!\n");
11633 break;
11634 case NODE_TEST_ALL:
11635 xmlGenericError(xmlGenericErrorContext,
11636 " searching for *\n");
11637 break;
11638 case NODE_TEST_NS:
11639 xmlGenericError(xmlGenericErrorContext,
11640 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011641 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011642 break;
11643 case NODE_TEST_NAME:
11644 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011645 " searching for name %s\n", op->value5);
11646 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011647 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011648 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011649 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011650 }
11651 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011652}
11653#endif /* DEBUG_STEP */
11654
11655static int
11656xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11657 xmlXPathStepOpPtr op,
11658 xmlNodeSetPtr set,
11659 int contextSize,
11660 int hasNsNodes)
11661{
11662 if (op->ch1 != -1) {
11663 xmlXPathCompExprPtr comp = ctxt->comp;
11664 /*
11665 * Process inner predicates first.
11666 */
11667 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11668 /*
11669 * TODO: raise an internal error.
11670 */
11671 }
11672 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11673 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11674 CHECK_ERROR0;
11675 if (contextSize <= 0)
11676 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011677 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011678 if (op->ch2 != -1) {
11679 xmlXPathContextPtr xpctxt = ctxt->context;
11680 xmlNodePtr contextNode, oldContextNode;
11681 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011682 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011683 xmlXPathStepOpPtr exprOp;
11684 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11685
11686#ifdef LIBXML_XPTR_ENABLED
11687 /*
11688 * URGENT TODO: Check the following:
11689 * We don't expect location sets if evaluating prediates, right?
11690 * Only filters should expect location sets, right?
11691 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011692#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011693 /*
11694 * SPEC XPath 1.0:
11695 * "For each node in the node-set to be filtered, the
11696 * PredicateExpr is evaluated with that node as the
11697 * context node, with the number of nodes in the
11698 * node-set as the context size, and with the proximity
11699 * position of the node in the node-set with respect to
11700 * the axis as the context position;"
11701 * @oldset is the node-set" to be filtered.
11702 *
11703 * SPEC XPath 1.0:
11704 * "only predicates change the context position and
11705 * context size (see [2.4 Predicates])."
11706 * Example:
11707 * node-set context pos
11708 * nA 1
11709 * nB 2
11710 * nC 3
11711 * After applying predicate [position() > 1] :
11712 * node-set context pos
11713 * nB 1
11714 * nC 2
11715 */
11716 oldContextNode = xpctxt->node;
11717 oldContextDoc = xpctxt->doc;
11718 /*
11719 * Get the expression of this predicate.
11720 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011721 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011722 newContextSize = 0;
11723 for (i = 0; i < set->nodeNr; i++) {
11724 if (set->nodeTab[i] == NULL)
11725 continue;
11726
11727 contextNode = set->nodeTab[i];
11728 xpctxt->node = contextNode;
11729 xpctxt->contextSize = contextSize;
11730 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011731
11732 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011733 * Also set the xpath document in case things like
11734 * key() are evaluated in the predicate.
11735 */
11736 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11737 (contextNode->doc != NULL))
11738 xpctxt->doc = contextNode->doc;
11739 /*
11740 * Evaluate the predicate expression with 1 context node
11741 * at a time; this node is packaged into a node set; this
11742 * node set is handed over to the evaluation mechanism.
11743 */
11744 if (contextObj == NULL)
11745 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011746 else {
11747 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11748 contextNode) < 0) {
11749 ctxt->error = XPATH_MEMORY_ERROR;
11750 goto evaluation_exit;
11751 }
11752 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011753
11754 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011755
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011756 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011757
William M. Brack0bcec062007-02-14 02:15:19 +000011758 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11759 xmlXPathNodeSetClear(set, hasNsNodes);
11760 newContextSize = 0;
11761 goto evaluation_exit;
11762 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011763
11764 if (res != 0) {
11765 newContextSize++;
11766 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011767 /*
11768 * Remove the entry from the initial node set.
11769 */
11770 set->nodeTab[i] = NULL;
11771 if (contextNode->type == XML_NAMESPACE_DECL)
11772 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011773 }
11774 if (ctxt->value == contextObj) {
11775 /*
11776 * Don't free the temporary XPath object holding the
11777 * context node, in order to avoid massive recreation
11778 * inside this loop.
11779 */
11780 valuePop(ctxt);
11781 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11782 } else {
11783 /*
11784 * TODO: The object was lost in the evaluation machinery.
11785 * Can this happen? Maybe in internal-error cases.
11786 */
11787 contextObj = NULL;
11788 }
11789 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011790
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011791 if (contextObj != NULL) {
11792 if (ctxt->value == contextObj)
11793 valuePop(ctxt);
11794 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011795 }
William M. Brack0bcec062007-02-14 02:15:19 +000011796evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011797 if (exprRes != NULL)
11798 xmlXPathReleaseObject(ctxt->context, exprRes);
11799 /*
11800 * Reset/invalidate the context.
11801 */
11802 xpctxt->node = oldContextNode;
11803 xpctxt->doc = oldContextDoc;
11804 xpctxt->contextSize = -1;
11805 xpctxt->proximityPosition = -1;
11806 return(newContextSize);
11807 }
11808 return(contextSize);
11809}
11810
11811static int
11812xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11813 xmlXPathStepOpPtr op,
11814 xmlNodeSetPtr set,
11815 int contextSize,
11816 int minPos,
11817 int maxPos,
11818 int hasNsNodes)
11819{
11820 if (op->ch1 != -1) {
11821 xmlXPathCompExprPtr comp = ctxt->comp;
11822 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11823 /*
11824 * TODO: raise an internal error.
11825 */
11826 }
11827 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11828 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11829 CHECK_ERROR0;
11830 if (contextSize <= 0)
11831 return(0);
11832 }
11833 /*
11834 * Check if the node set contains a sufficient number of nodes for
11835 * the requested range.
11836 */
11837 if (contextSize < minPos) {
11838 xmlXPathNodeSetClear(set, hasNsNodes);
11839 return(0);
11840 }
11841 if (op->ch2 == -1) {
11842 /*
11843 * TODO: Can this ever happen?
11844 */
11845 return (contextSize);
11846 } else {
11847 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011848 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011849 xmlXPathStepOpPtr exprOp;
11850 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11851 xmlNodePtr oldContextNode, contextNode = NULL;
11852 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011853 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011854
11855#ifdef LIBXML_XPTR_ENABLED
11856 /*
11857 * URGENT TODO: Check the following:
11858 * We don't expect location sets if evaluating prediates, right?
11859 * Only filters should expect location sets, right?
11860 */
11861#endif /* LIBXML_XPTR_ENABLED */
11862
11863 /*
11864 * Save old context.
11865 */
11866 oldContextNode = xpctxt->node;
11867 oldContextDoc = xpctxt->doc;
11868 /*
11869 * Get the expression of this predicate.
11870 */
11871 exprOp = &ctxt->comp->steps[op->ch2];
11872 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011873 xmlXPathObjectPtr tmp;
11874
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011875 if (set->nodeTab[i] == NULL)
11876 continue;
11877
11878 contextNode = set->nodeTab[i];
11879 xpctxt->node = contextNode;
11880 xpctxt->contextSize = contextSize;
11881 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011882
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011883 /*
11884 * Initialize the new set.
11885 * Also set the xpath document in case things like
11886 * key() evaluation are attempted on the predicate
11887 */
11888 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11889 (contextNode->doc != NULL))
11890 xpctxt->doc = contextNode->doc;
11891 /*
11892 * Evaluate the predicate expression with 1 context node
11893 * at a time; this node is packaged into a node set; this
11894 * node set is handed over to the evaluation mechanism.
11895 */
11896 if (contextObj == NULL)
11897 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
Daniel Veillard1bd45d12012-09-05 15:35:19 +080011898 else {
11899 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11900 contextNode) < 0) {
11901 ctxt->error = XPATH_MEMORY_ERROR;
11902 goto evaluation_exit;
11903 }
11904 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011905
Daniel Veillardf5048b32011-08-18 17:10:13 +080011906 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011907 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011908 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011909 tmp = valuePop(ctxt);
11910 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011911
William M. Brackf1794562007-08-23 12:58:13 +000011912 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011913 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011914 /*
11915 * Free up the result
11916 * then pop off contextObj, which will be freed later
11917 */
11918 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011919 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011920 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011921 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011922 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011923 /* push the result back onto the stack */
11924 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011925
11926 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011927 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011928
11929 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011930 /*
11931 * Fits in the requested range.
11932 */
11933 newContextSize++;
11934 if (minPos == maxPos) {
11935 /*
11936 * Only 1 node was requested.
11937 */
11938 if (contextNode->type == XML_NAMESPACE_DECL) {
11939 /*
11940 * As always: take care of those nasty
11941 * namespace nodes.
11942 */
11943 set->nodeTab[i] = NULL;
11944 }
11945 xmlXPathNodeSetClear(set, hasNsNodes);
11946 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011947 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011948 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011949 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011950 if (pos == maxPos) {
11951 /*
11952 * We are done.
11953 */
11954 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11955 goto evaluation_exit;
11956 }
11957 } else {
11958 /*
11959 * Remove the entry from the initial node set.
11960 */
11961 set->nodeTab[i] = NULL;
11962 if (contextNode->type == XML_NAMESPACE_DECL)
11963 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11964 }
11965 if (exprRes != NULL) {
11966 xmlXPathReleaseObject(ctxt->context, exprRes);
11967 exprRes = NULL;
11968 }
11969 if (ctxt->value == contextObj) {
11970 /*
11971 * Don't free the temporary XPath object holding the
11972 * context node, in order to avoid massive recreation
11973 * inside this loop.
11974 */
11975 valuePop(ctxt);
11976 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11977 } else {
11978 /*
11979 * The object was lost in the evaluation machinery.
11980 * Can this happen? Maybe in case of internal-errors.
11981 */
11982 contextObj = NULL;
11983 }
11984 }
11985 goto evaluation_exit;
11986
11987evaluation_error:
11988 xmlXPathNodeSetClear(set, hasNsNodes);
11989 newContextSize = 0;
11990
11991evaluation_exit:
11992 if (contextObj != NULL) {
11993 if (ctxt->value == contextObj)
11994 valuePop(ctxt);
11995 xmlXPathReleaseObject(xpctxt, contextObj);
11996 }
11997 if (exprRes != NULL)
11998 xmlXPathReleaseObject(ctxt->context, exprRes);
11999 /*
12000 * Reset/invalidate the context.
12001 */
12002 xpctxt->node = oldContextNode;
12003 xpctxt->doc = oldContextDoc;
12004 xpctxt->contextSize = -1;
12005 xpctxt->proximityPosition = -1;
12006 return(newContextSize);
12007 }
12008 return(contextSize);
12009}
12010
12011static int
12012xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000012013 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012014 int *maxPos)
12015{
12016
12017 xmlXPathStepOpPtr exprOp;
12018
12019 /*
12020 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12021 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012022
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012023 /*
12024 * If not -1, then ch1 will point to:
12025 * 1) For predicates (XPATH_OP_PREDICATE):
12026 * - an inner predicate operator
12027 * 2) For filters (XPATH_OP_FILTER):
12028 * - an inner filter operater OR
12029 * - an expression selecting the node set.
12030 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012031 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012032 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12033 return(0);
12034
12035 if (op->ch2 != -1) {
12036 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012037 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012038 return(0);
12039
12040 if ((exprOp != NULL) &&
12041 (exprOp->op == XPATH_OP_VALUE) &&
12042 (exprOp->value4 != NULL) &&
12043 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12044 {
12045 /*
12046 * We have a "[n]" predicate here.
12047 * TODO: Unfortunately this simplistic test here is not
12048 * able to detect a position() predicate in compound
12049 * expressions like "[@attr = 'a" and position() = 1],
12050 * and even not the usage of position() in
12051 * "[position() = 1]"; thus - obviously - a position-range,
12052 * like it "[position() < 5]", is also not detected.
12053 * Maybe we could rewrite the AST to ease the optimization.
12054 */
12055 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012056
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012057 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12058 (float) *maxPos)
Daniel Veillard45490ae2008-07-29 09:13:19 +000012059 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012060 return(1);
12061 }
12062 }
12063 return(0);
12064}
12065
12066static int
12067xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12068 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012069 xmlNodePtr * first, xmlNodePtr * last,
12070 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012071{
12072
12073#define XP_TEST_HIT \
12074 if (hasAxisRange != 0) { \
12075 if (++pos == maxPos) { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012076 if (addNode(seq, cur) < 0) \
12077 ctxt->error = XPATH_MEMORY_ERROR; \
12078 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012079 } else { \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012080 if (addNode(seq, cur) < 0) \
12081 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012082 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012083
12084#define XP_TEST_HIT_NS \
12085 if (hasAxisRange != 0) { \
12086 if (++pos == maxPos) { \
12087 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012088 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12089 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012090 goto axis_range_end; } \
12091 } else { \
12092 hasNsNodes = 1; \
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012093 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12094 ctxt->error = XPATH_MEMORY_ERROR; \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012095 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012096
12097 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12098 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12099 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12100 const xmlChar *prefix = op->value4;
12101 const xmlChar *name = op->value5;
12102 const xmlChar *URI = NULL;
12103
12104#ifdef DEBUG_STEP
12105 int nbMatches = 0, prevMatches = 0;
12106#endif
12107 int total = 0, hasNsNodes = 0;
12108 /* The popped object holding the context nodes */
12109 xmlXPathObjectPtr obj;
12110 /* The set of context nodes for the node tests */
12111 xmlNodeSetPtr contextSeq;
12112 int contextIdx;
12113 xmlNodePtr contextNode;
12114 /* The context node for a compound traversal */
12115 xmlNodePtr outerContextNode;
12116 /* The final resulting node set wrt to all context nodes */
12117 xmlNodeSetPtr outSeq;
12118 /*
12119 * The temporary resulting node set wrt 1 context node.
12120 * Used to feed predicate evaluation.
12121 */
12122 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012123 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012124 /* First predicate operator */
12125 xmlXPathStepOpPtr predOp;
12126 int maxPos; /* The requested position() (when a "[n]" predicate) */
12127 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012128 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012129
12130 xmlXPathTraversalFunction next = NULL;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012131 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012132 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012133 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012134 xmlXPathContextPtr xpctxt = ctxt->context;
12135
12136
12137 CHECK_TYPE0(XPATH_NODESET);
12138 obj = valuePop(ctxt);
12139 /*
12140 * Setup namespaces.
12141 */
12142 if (prefix != NULL) {
12143 URI = xmlXPathNsLookup(xpctxt, prefix);
12144 if (URI == NULL) {
12145 xmlXPathReleaseObject(xpctxt, obj);
12146 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12147 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012148 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012149 /*
12150 * Setup axis.
12151 *
12152 * MAYBE FUTURE TODO: merging optimizations:
12153 * - If the nodes to be traversed wrt to the initial nodes and
12154 * the current axis cannot overlap, then we could avoid searching
12155 * for duplicates during the merge.
12156 * But the question is how/when to evaluate if they cannot overlap.
12157 * Example: if we know that for two initial nodes, the one is
12158 * not in the ancestor-or-self axis of the other, then we could safely
12159 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12160 * the descendant-or-self axis.
12161 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012162 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12163 switch (axis) {
12164 case AXIS_ANCESTOR:
12165 first = NULL;
12166 next = xmlXPathNextAncestor;
12167 break;
12168 case AXIS_ANCESTOR_OR_SELF:
12169 first = NULL;
12170 next = xmlXPathNextAncestorOrSelf;
12171 break;
12172 case AXIS_ATTRIBUTE:
12173 first = NULL;
12174 last = NULL;
12175 next = xmlXPathNextAttribute;
12176 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12177 break;
12178 case AXIS_CHILD:
12179 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012180 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12181 (type == NODE_TYPE_NODE))
12182 {
12183 /*
12184 * Optimization if an element node type is 'element'.
12185 */
12186 next = xmlXPathNextChildElement;
12187 } else
12188 next = xmlXPathNextChild;
12189 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12190 break;
12191 case AXIS_DESCENDANT:
12192 last = NULL;
12193 next = xmlXPathNextDescendant;
12194 break;
12195 case AXIS_DESCENDANT_OR_SELF:
12196 last = NULL;
12197 next = xmlXPathNextDescendantOrSelf;
12198 break;
12199 case AXIS_FOLLOWING:
12200 last = NULL;
12201 next = xmlXPathNextFollowing;
12202 break;
12203 case AXIS_FOLLOWING_SIBLING:
12204 last = NULL;
12205 next = xmlXPathNextFollowingSibling;
12206 break;
12207 case AXIS_NAMESPACE:
12208 first = NULL;
12209 last = NULL;
12210 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12211 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12212 break;
12213 case AXIS_PARENT:
12214 first = NULL;
12215 next = xmlXPathNextParent;
12216 break;
12217 case AXIS_PRECEDING:
12218 first = NULL;
12219 next = xmlXPathNextPrecedingInternal;
12220 break;
12221 case AXIS_PRECEDING_SIBLING:
12222 first = NULL;
12223 next = xmlXPathNextPrecedingSibling;
12224 break;
12225 case AXIS_SELF:
12226 first = NULL;
12227 last = NULL;
12228 next = xmlXPathNextSelf;
12229 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12230 break;
12231 }
12232
12233#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012234 xmlXPathDebugDumpStepAxis(op,
12235 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012236#endif
12237
12238 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012239 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012240 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012241 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012242 contextSeq = obj->nodesetval;
12243 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12244 xmlXPathReleaseObject(xpctxt, obj);
12245 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12246 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012247 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012248 /*
12249 * Predicate optimization ---------------------------------------------
12250 * If this step has a last predicate, which contains a position(),
12251 * then we'll optimize (although not exactly "position()", but only
12252 * the short-hand form, i.e., "[n]".
12253 *
12254 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012255 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012256 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12257 * ROOT -- op->ch1
12258 * PREDICATE -- op->ch2 (predOp)
12259 * PREDICATE -- predOp->ch1 = [parent::bar]
12260 * SORT
12261 * COLLECT 'parent' 'name' 'node' bar
12262 * NODE
12263 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12264 *
12265 */
12266 maxPos = 0;
12267 predOp = NULL;
12268 hasPredicateRange = 0;
12269 hasAxisRange = 0;
12270 if (op->ch2 != -1) {
12271 /*
12272 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12273 */
12274 predOp = &ctxt->comp->steps[op->ch2];
12275 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12276 if (predOp->ch1 != -1) {
12277 /*
12278 * Use the next inner predicate operator.
12279 */
12280 predOp = &ctxt->comp->steps[predOp->ch1];
12281 hasPredicateRange = 1;
12282 } else {
12283 /*
12284 * There's no other predicate than the [n] predicate.
12285 */
12286 predOp = NULL;
12287 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012288 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012289 }
12290 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012291 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012292 /*
12293 * Axis traversal -----------------------------------------------------
12294 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012295 /*
12296 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012297 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012298 * - For the namespace axis, the principal node type is namespace.
12299 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012300 *
12301 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012302 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012303 * select all element children of the context node
12304 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012305 oldContextNode = xpctxt->node;
12306 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012307 outSeq = NULL;
12308 seq = NULL;
12309 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012310 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012311 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012312
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012313
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012314 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12315 (ctxt->error == XPATH_EXPRESSION_OK)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012316 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012317
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012318 if (seq == NULL) {
12319 seq = xmlXPathNodeSetCreate(NULL);
12320 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012321 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012322 goto error;
12323 }
12324 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012325 /*
12326 * Traverse the axis and test the nodes.
12327 */
12328 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012329 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012330 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012331 do {
12332 cur = next(ctxt, cur);
12333 if (cur == NULL)
12334 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012335
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012336 /*
12337 * QUESTION TODO: What does the "first" and "last" stuff do?
12338 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012339 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012340 if (*first == cur)
12341 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012342 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012343#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012344 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012345#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012346 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012347#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012348 {
12349 break;
12350 }
12351 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012352 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012353 if (*last == cur)
12354 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012355 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012356#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012357 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012358#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012359 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012360#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012361 {
12362 break;
12363 }
12364 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012365
12366 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012367
Daniel Veillardf06307e2001-07-03 10:35:50 +000012368#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012369 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12370#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012371
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012372 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012373 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012374 total = 0;
12375 STRANGE
12376 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012377 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012378 /*
12379 * TODO: Don't we need to use
12380 * xmlXPathNodeSetAddNs() for namespace nodes here?
12381 * Surprisingly, some c14n tests fail, if we do this.
12382 */
12383 if (type == NODE_TYPE_NODE) {
12384 switch (cur->type) {
12385 case XML_DOCUMENT_NODE:
12386 case XML_HTML_DOCUMENT_NODE:
12387#ifdef LIBXML_DOCB_ENABLED
12388 case XML_DOCB_DOCUMENT_NODE:
12389#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012390 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012391 case XML_ATTRIBUTE_NODE:
12392 case XML_PI_NODE:
12393 case XML_COMMENT_NODE:
12394 case XML_CDATA_SECTION_NODE:
12395 case XML_TEXT_NODE:
12396 case XML_NAMESPACE_DECL:
12397 XP_TEST_HIT
12398 break;
12399 default:
12400 break;
12401 }
12402 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012403 if (type == XML_NAMESPACE_DECL)
12404 XP_TEST_HIT_NS
12405 else
12406 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012407 } else if ((type == NODE_TYPE_TEXT) &&
12408 (cur->type == XML_CDATA_SECTION_NODE))
12409 {
12410 XP_TEST_HIT
12411 }
12412 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012413 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012414 if ((cur->type == XML_PI_NODE) &&
12415 ((name == NULL) || xmlStrEqual(name, cur->name)))
12416 {
12417 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012418 }
12419 break;
12420 case NODE_TEST_ALL:
12421 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012422 if (cur->type == XML_ATTRIBUTE_NODE)
12423 {
12424 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012425 }
12426 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012427 if (cur->type == XML_NAMESPACE_DECL)
12428 {
12429 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012430 }
12431 } else {
12432 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012433 if (prefix == NULL)
12434 {
12435 XP_TEST_HIT
12436
Daniel Veillardf06307e2001-07-03 10:35:50 +000012437 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012438 (xmlStrEqual(URI, cur->ns->href)))
12439 {
12440 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012441 }
12442 }
12443 }
12444 break;
12445 case NODE_TEST_NS:{
12446 TODO;
12447 break;
12448 }
12449 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012450 if (axis == AXIS_ATTRIBUTE) {
12451 if (cur->type != XML_ATTRIBUTE_NODE)
12452 break;
12453 } else if (axis == AXIS_NAMESPACE) {
12454 if (cur->type != XML_NAMESPACE_DECL)
12455 break;
12456 } else {
12457 if (cur->type != XML_ELEMENT_NODE)
12458 break;
12459 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012460 switch (cur->type) {
12461 case XML_ELEMENT_NODE:
12462 if (xmlStrEqual(name, cur->name)) {
12463 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012464 if (cur->ns == NULL)
12465 {
12466 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012467 }
12468 } else {
12469 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012470 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012471 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012472 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012473 }
12474 }
12475 }
12476 break;
12477 case XML_ATTRIBUTE_NODE:{
12478 xmlAttrPtr attr = (xmlAttrPtr) cur;
12479
12480 if (xmlStrEqual(name, attr->name)) {
12481 if (prefix == NULL) {
12482 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012483 (attr->ns->prefix == NULL))
12484 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012485 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012486 }
12487 } else {
12488 if ((attr->ns != NULL) &&
12489 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012490 attr->ns->href)))
12491 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012492 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012493 }
12494 }
12495 }
12496 break;
12497 }
12498 case XML_NAMESPACE_DECL:
12499 if (cur->type == XML_NAMESPACE_DECL) {
12500 xmlNsPtr ns = (xmlNsPtr) cur;
12501
12502 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012503 && (xmlStrEqual(ns->prefix, name)))
12504 {
12505 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012506 }
12507 }
12508 break;
12509 default:
12510 break;
12511 }
12512 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012513 } /* switch(test) */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012514 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012515
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012516 goto apply_predicates;
12517
Daniel Veillard45490ae2008-07-29 09:13:19 +000012518axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012519 /*
12520 * We have a "/foo[n]", and position() = n was reached.
12521 * Note that we can have as well "/foo/::parent::foo[1]", so
12522 * a duplicate-aware merge is still needed.
12523 * Merge with the result.
12524 */
12525 if (outSeq == NULL) {
12526 outSeq = seq;
12527 seq = NULL;
12528 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012529 outSeq = mergeAndClear(outSeq, seq, 0);
12530 /*
12531 * Break if only a true/false result was requested.
12532 */
12533 if (toBool)
12534 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012535 continue;
12536
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012537first_hit: /* ---------------------------------------------------------- */
12538 /*
12539 * Break if only a true/false result was requested and
12540 * no predicates existed and a node test succeeded.
12541 */
12542 if (outSeq == NULL) {
12543 outSeq = seq;
12544 seq = NULL;
12545 } else
12546 outSeq = mergeAndClear(outSeq, seq, 0);
12547 break;
12548
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012549#ifdef DEBUG_STEP
12550 if (seq != NULL)
12551 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012552#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012553
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012554apply_predicates: /* --------------------------------------------------- */
Daniel Veillard1bd45d12012-09-05 15:35:19 +080012555 if (ctxt->error != XPATH_EXPRESSION_OK)
12556 goto error;
12557
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012558 /*
12559 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012560 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012561 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12562 /*
12563 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012564 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012565 /*
12566 * QUESTION TODO: The old predicate evaluation took into
12567 * account location-sets.
12568 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12569 * Do we expect such a set here?
12570 * All what I learned now from the evaluation semantics
12571 * does not indicate that a location-set will be processed
12572 * here, so this looks OK.
Daniel Veillardf8e3db02012-09-11 13:26:36 +080012573 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012574 /*
12575 * Iterate over all predicates, starting with the outermost
12576 * predicate.
12577 * TODO: Problem: we cannot execute the inner predicates first
12578 * since we cannot go back *up* the operator tree!
12579 * Options we have:
12580 * 1) Use of recursive functions (like is it currently done
12581 * via xmlXPathCompOpEval())
12582 * 2) Add a predicate evaluation information stack to the
12583 * context struct
12584 * 3) Change the way the operators are linked; we need a
12585 * "parent" field on xmlXPathStepOp
12586 *
12587 * For the moment, I'll try to solve this with a recursive
12588 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012589 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012590 size = seq->nodeNr;
12591 if (hasPredicateRange != 0)
12592 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12593 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12594 else
12595 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12596 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012597
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012598 if (ctxt->error != XPATH_EXPRESSION_OK) {
12599 total = 0;
12600 goto error;
12601 }
12602 /*
12603 * Add the filtered set of nodes to the result node set.
12604 */
12605 if (newSize == 0) {
12606 /*
12607 * The predicates filtered all nodes out.
12608 */
12609 xmlXPathNodeSetClear(seq, hasNsNodes);
12610 } else if (seq->nodeNr > 0) {
12611 /*
12612 * Add to result set.
12613 */
12614 if (outSeq == NULL) {
12615 if (size != newSize) {
12616 /*
12617 * We need to merge and clear here, since
12618 * the sequence will contained NULLed entries.
12619 */
12620 outSeq = mergeAndClear(NULL, seq, 1);
12621 } else {
12622 outSeq = seq;
12623 seq = NULL;
12624 }
12625 } else
12626 outSeq = mergeAndClear(outSeq, seq,
12627 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012628 /*
12629 * Break if only a true/false result was requested.
12630 */
12631 if (toBool)
12632 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012633 }
12634 } else if (seq->nodeNr > 0) {
12635 /*
12636 * Add to result set.
12637 */
12638 if (outSeq == NULL) {
12639 outSeq = seq;
12640 seq = NULL;
12641 } else {
12642 outSeq = mergeAndClear(outSeq, seq, 0);
12643 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012644 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012645 }
12646
12647error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012648 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012649 /*
12650 * QUESTION TODO: What does this do and why?
12651 * TODO: Do we have to do this also for the "error"
12652 * cleanup further down?
12653 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012654 ctxt->value->boolval = 1;
12655 ctxt->value->user = obj->user;
12656 obj->user = NULL;
12657 obj->boolval = 0;
12658 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012659 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012660
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012661 /*
12662 * Ensure we return at least an emtpy set.
12663 */
12664 if (outSeq == NULL) {
12665 if ((seq != NULL) && (seq->nodeNr == 0))
12666 outSeq = seq;
12667 else
12668 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012669 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012670 }
12671 if ((seq != NULL) && (seq != outSeq)) {
12672 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012673 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012674 /*
12675 * Hand over the result. Better to push the set also in
12676 * case of errors.
12677 */
12678 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12679 /*
12680 * Reset the context node.
12681 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012682 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012683
12684#ifdef DEBUG_STEP
12685 xmlGenericError(xmlGenericErrorContext,
12686 "\nExamined %d nodes, found %d nodes at that step\n",
12687 total, nbMatches);
12688#endif
12689
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012690 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012691}
12692
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012693static int
12694xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12695 xmlXPathStepOpPtr op, xmlNodePtr * first);
12696
Daniel Veillardf06307e2001-07-03 10:35:50 +000012697/**
12698 * xmlXPathCompOpEvalFirst:
12699 * @ctxt: the XPath parser context with the compiled expression
12700 * @op: an XPath compiled operation
12701 * @first: the first elem found so far
12702 *
12703 * Evaluate the Precompiled XPath operation searching only the first
12704 * element in document order
12705 *
12706 * Returns the number of examined objects.
12707 */
12708static int
12709xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12710 xmlXPathStepOpPtr op, xmlNodePtr * first)
12711{
12712 int total = 0, cur;
12713 xmlXPathCompExprPtr comp;
12714 xmlXPathObjectPtr arg1, arg2;
12715
Daniel Veillard556c6682001-10-06 09:59:51 +000012716 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012717 comp = ctxt->comp;
12718 switch (op->op) {
12719 case XPATH_OP_END:
12720 return (0);
12721 case XPATH_OP_UNION:
12722 total =
12723 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12724 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012725 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012726 if ((ctxt->value != NULL)
12727 && (ctxt->value->type == XPATH_NODESET)
12728 && (ctxt->value->nodesetval != NULL)
12729 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12730 /*
12731 * limit tree traversing to first node in the result
12732 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012733 /*
12734 * OPTIMIZE TODO: This implicitely sorts
12735 * the result, even if not needed. E.g. if the argument
12736 * of the count() function, no sorting is needed.
12737 * OPTIMIZE TODO: How do we know if the node-list wasn't
12738 * aready sorted?
12739 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012740 if (ctxt->value->nodesetval->nodeNr > 1)
12741 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012742 *first = ctxt->value->nodesetval->nodeTab[0];
12743 }
12744 cur =
12745 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12746 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012747 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012748 CHECK_TYPE0(XPATH_NODESET);
12749 arg2 = valuePop(ctxt);
12750
12751 CHECK_TYPE0(XPATH_NODESET);
12752 arg1 = valuePop(ctxt);
12753
12754 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12755 arg2->nodesetval);
12756 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012757 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012758 /* optimizer */
12759 if (total > cur)
12760 xmlXPathCompSwap(op);
12761 return (total + cur);
12762 case XPATH_OP_ROOT:
12763 xmlXPathRoot(ctxt);
12764 return (0);
12765 case XPATH_OP_NODE:
12766 if (op->ch1 != -1)
12767 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012768 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012769 if (op->ch2 != -1)
12770 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012771 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012772 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12773 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012774 return (total);
12775 case XPATH_OP_RESET:
12776 if (op->ch1 != -1)
12777 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012778 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012779 if (op->ch2 != -1)
12780 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012781 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012782 ctxt->context->node = NULL;
12783 return (total);
12784 case XPATH_OP_COLLECT:{
12785 if (op->ch1 == -1)
12786 return (total);
12787
12788 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012789 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012790
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012791 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012792 return (total);
12793 }
12794 case XPATH_OP_VALUE:
12795 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012796 xmlXPathCacheObjectCopy(ctxt->context,
12797 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012798 return (0);
12799 case XPATH_OP_SORT:
12800 if (op->ch1 != -1)
12801 total +=
12802 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12803 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012804 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012805 if ((ctxt->value != NULL)
12806 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012807 && (ctxt->value->nodesetval != NULL)
12808 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012809 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12810 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012811#ifdef XP_OPTIMIZED_FILTER_FIRST
12812 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012813 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012814 return (total);
12815#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012816 default:
12817 return (xmlXPathCompOpEval(ctxt, op));
12818 }
12819}
12820
12821/**
12822 * xmlXPathCompOpEvalLast:
12823 * @ctxt: the XPath parser context with the compiled expression
12824 * @op: an XPath compiled operation
12825 * @last: the last elem found so far
12826 *
12827 * Evaluate the Precompiled XPath operation searching only the last
12828 * element in document order
12829 *
William M. Brack08171912003-12-29 02:52:11 +000012830 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012831 */
12832static int
12833xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12834 xmlNodePtr * last)
12835{
12836 int total = 0, cur;
12837 xmlXPathCompExprPtr comp;
12838 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012839 xmlNodePtr bak;
12840 xmlDocPtr bakd;
12841 int pp;
12842 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012843
Daniel Veillard556c6682001-10-06 09:59:51 +000012844 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012845 comp = ctxt->comp;
12846 switch (op->op) {
12847 case XPATH_OP_END:
12848 return (0);
12849 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012850 bakd = ctxt->context->doc;
12851 bak = ctxt->context->node;
12852 pp = ctxt->context->proximityPosition;
12853 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012854 total =
12855 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012856 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012857 if ((ctxt->value != NULL)
12858 && (ctxt->value->type == XPATH_NODESET)
12859 && (ctxt->value->nodesetval != NULL)
12860 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12861 /*
12862 * limit tree traversing to first node in the result
12863 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012864 if (ctxt->value->nodesetval->nodeNr > 1)
12865 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012866 *last =
12867 ctxt->value->nodesetval->nodeTab[ctxt->value->
12868 nodesetval->nodeNr -
12869 1];
12870 }
William M. Brackce4fc562004-01-22 02:47:18 +000012871 ctxt->context->doc = bakd;
12872 ctxt->context->node = bak;
12873 ctxt->context->proximityPosition = pp;
12874 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012875 cur =
12876 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012877 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012878 if ((ctxt->value != NULL)
12879 && (ctxt->value->type == XPATH_NODESET)
12880 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012881 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012882 }
12883 CHECK_TYPE0(XPATH_NODESET);
12884 arg2 = valuePop(ctxt);
12885
12886 CHECK_TYPE0(XPATH_NODESET);
12887 arg1 = valuePop(ctxt);
12888
12889 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12890 arg2->nodesetval);
12891 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012892 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012893 /* optimizer */
12894 if (total > cur)
12895 xmlXPathCompSwap(op);
12896 return (total + cur);
12897 case XPATH_OP_ROOT:
12898 xmlXPathRoot(ctxt);
12899 return (0);
12900 case XPATH_OP_NODE:
12901 if (op->ch1 != -1)
12902 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012903 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012904 if (op->ch2 != -1)
12905 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012906 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012907 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12908 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012909 return (total);
12910 case XPATH_OP_RESET:
12911 if (op->ch1 != -1)
12912 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012913 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012914 if (op->ch2 != -1)
12915 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012916 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012917 ctxt->context->node = NULL;
12918 return (total);
12919 case XPATH_OP_COLLECT:{
12920 if (op->ch1 == -1)
12921 return (0);
12922
12923 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012924 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012925
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012926 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012927 return (total);
12928 }
12929 case XPATH_OP_VALUE:
12930 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012931 xmlXPathCacheObjectCopy(ctxt->context,
12932 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012933 return (0);
12934 case XPATH_OP_SORT:
12935 if (op->ch1 != -1)
12936 total +=
12937 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12938 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012939 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012940 if ((ctxt->value != NULL)
12941 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012942 && (ctxt->value->nodesetval != NULL)
12943 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012944 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12945 return (total);
12946 default:
12947 return (xmlXPathCompOpEval(ctxt, op));
12948 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012949}
12950
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012951#ifdef XP_OPTIMIZED_FILTER_FIRST
12952static int
12953xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12954 xmlXPathStepOpPtr op, xmlNodePtr * first)
12955{
12956 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012957 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012958 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012959 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012960 xmlNodeSetPtr oldset;
12961 xmlNodePtr oldnode;
12962 xmlDocPtr oldDoc;
12963 int i;
12964
12965 CHECK_ERROR0;
12966 comp = ctxt->comp;
12967 /*
12968 * Optimization for ()[last()] selection i.e. the last elem
12969 */
12970 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12971 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12972 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12973 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012974
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012975 if ((f != -1) &&
12976 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12977 (comp->steps[f].value5 == NULL) &&
12978 (comp->steps[f].value == 0) &&
12979 (comp->steps[f].value4 != NULL) &&
12980 (xmlStrEqual
12981 (comp->steps[f].value4, BAD_CAST "last"))) {
12982 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012983
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012984 total +=
12985 xmlXPathCompOpEvalLast(ctxt,
12986 &comp->steps[op->ch1],
12987 &last);
12988 CHECK_ERROR0;
12989 /*
12990 * The nodeset should be in document order,
12991 * Keep only the last value
12992 */
12993 if ((ctxt->value != NULL) &&
12994 (ctxt->value->type == XPATH_NODESET) &&
12995 (ctxt->value->nodesetval != NULL) &&
12996 (ctxt->value->nodesetval->nodeTab != NULL) &&
12997 (ctxt->value->nodesetval->nodeNr > 1)) {
12998 ctxt->value->nodesetval->nodeTab[0] =
12999 ctxt->value->nodesetval->nodeTab[ctxt->
13000 value->
13001 nodesetval->
13002 nodeNr -
13003 1];
13004 ctxt->value->nodesetval->nodeNr = 1;
13005 *first = *(ctxt->value->nodesetval->nodeTab);
13006 }
13007 return (total);
13008 }
13009 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013010
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013011 if (op->ch1 != -1)
13012 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13013 CHECK_ERROR0;
13014 if (op->ch2 == -1)
13015 return (total);
13016 if (ctxt->value == NULL)
13017 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013018
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013019#ifdef LIBXML_XPTR_ENABLED
13020 oldnode = ctxt->context->node;
13021 /*
13022 * Hum are we filtering the result of an XPointer expression
13023 */
13024 if (ctxt->value->type == XPATH_LOCATIONSET) {
13025 xmlXPathObjectPtr tmp = NULL;
13026 xmlLocationSetPtr newlocset = NULL;
13027 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013028
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013029 /*
13030 * Extract the old locset, and then evaluate the result of the
13031 * expression for all the element in the locset. use it to grow
13032 * up a new locset.
13033 */
13034 CHECK_TYPE0(XPATH_LOCATIONSET);
13035 obj = valuePop(ctxt);
13036 oldlocset = obj->user;
13037 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013038
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013039 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13040 ctxt->context->contextSize = 0;
13041 ctxt->context->proximityPosition = 0;
13042 if (op->ch2 != -1)
13043 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13044 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013045 if (res != NULL) {
13046 xmlXPathReleaseObject(ctxt->context, res);
13047 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013048 valuePush(ctxt, obj);
13049 CHECK_ERROR0;
13050 return (total);
13051 }
13052 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013053
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013054 for (i = 0; i < oldlocset->locNr; i++) {
13055 /*
13056 * Run the evaluation with a node list made of a
13057 * single item in the nodelocset.
13058 */
13059 ctxt->context->node = oldlocset->locTab[i]->user;
13060 ctxt->context->contextSize = oldlocset->locNr;
13061 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013062 if (tmp == NULL) {
13063 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13064 ctxt->context->node);
13065 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013066 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13067 ctxt->context->node) < 0) {
13068 ctxt->error = XPATH_MEMORY_ERROR;
13069 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000013070 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013071 valuePush(ctxt, tmp);
13072 if (op->ch2 != -1)
13073 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13074 if (ctxt->error != XPATH_EXPRESSION_OK) {
13075 xmlXPathFreeObject(obj);
13076 return(0);
13077 }
13078 /*
13079 * The result of the evaluation need to be tested to
13080 * decided whether the filter succeeded or not
13081 */
13082 res = valuePop(ctxt);
13083 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13084 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013085 xmlXPathCacheObjectCopy(ctxt->context,
13086 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013087 }
13088 /*
13089 * Cleanup
13090 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013091 if (res != NULL) {
13092 xmlXPathReleaseObject(ctxt->context, res);
13093 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013094 if (ctxt->value == tmp) {
13095 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013096 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013097 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013098 * REVISIT TODO: Don't create a temporary nodeset
13099 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013100 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013101 /* OLD: xmlXPathFreeObject(res); */
13102 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013103 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013104 ctxt->context->node = NULL;
13105 /*
13106 * Only put the first node in the result, then leave.
13107 */
13108 if (newlocset->locNr > 0) {
13109 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13110 break;
13111 }
13112 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013113 if (tmp != NULL) {
13114 xmlXPathReleaseObject(ctxt->context, tmp);
13115 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013116 /*
13117 * The result is used as the new evaluation locset.
13118 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013119 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013120 ctxt->context->node = NULL;
13121 ctxt->context->contextSize = -1;
13122 ctxt->context->proximityPosition = -1;
13123 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13124 ctxt->context->node = oldnode;
13125 return (total);
13126 }
13127#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013128
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013129 /*
13130 * Extract the old set, and then evaluate the result of the
13131 * expression for all the element in the set. use it to grow
13132 * up a new set.
13133 */
13134 CHECK_TYPE0(XPATH_NODESET);
13135 obj = valuePop(ctxt);
13136 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013137
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013138 oldnode = ctxt->context->node;
13139 oldDoc = ctxt->context->doc;
13140 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013141
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013142 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13143 ctxt->context->contextSize = 0;
13144 ctxt->context->proximityPosition = 0;
13145 /* QUESTION TODO: Why was this code commented out?
13146 if (op->ch2 != -1)
13147 total +=
13148 xmlXPathCompOpEval(ctxt,
13149 &comp->steps[op->ch2]);
13150 CHECK_ERROR0;
13151 res = valuePop(ctxt);
13152 if (res != NULL)
13153 xmlXPathFreeObject(res);
13154 */
13155 valuePush(ctxt, obj);
13156 ctxt->context->node = oldnode;
13157 CHECK_ERROR0;
13158 } else {
13159 xmlNodeSetPtr newset;
13160 xmlXPathObjectPtr tmp = NULL;
13161 /*
13162 * Initialize the new set.
13163 * Also set the xpath document in case things like
13164 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013165 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013166 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013167 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013168
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013169 for (i = 0; i < oldset->nodeNr; i++) {
13170 /*
13171 * Run the evaluation with a node list made of
13172 * a single item in the nodeset.
13173 */
13174 ctxt->context->node = oldset->nodeTab[i];
13175 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13176 (oldset->nodeTab[i]->doc != NULL))
13177 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013178 if (tmp == NULL) {
13179 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13180 ctxt->context->node);
13181 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013182 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13183 ctxt->context->node) < 0) {
13184 ctxt->error = XPATH_MEMORY_ERROR;
13185 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013186 }
13187 valuePush(ctxt, tmp);
13188 ctxt->context->contextSize = oldset->nodeNr;
13189 ctxt->context->proximityPosition = i + 1;
13190 if (op->ch2 != -1)
13191 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13192 if (ctxt->error != XPATH_EXPRESSION_OK) {
13193 xmlXPathFreeNodeSet(newset);
13194 xmlXPathFreeObject(obj);
13195 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013196 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013197 /*
13198 * The result of the evaluation needs to be tested to
13199 * decide whether the filter succeeded or not
13200 */
13201 res = valuePop(ctxt);
13202 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013203 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13204 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013205 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013206 /*
13207 * Cleanup
13208 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013209 if (res != NULL) {
13210 xmlXPathReleaseObject(ctxt->context, res);
13211 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013212 if (ctxt->value == tmp) {
13213 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013214 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013215 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013216 * in order to avoid massive recreation inside this
13217 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013218 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013219 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013220 } else
13221 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013222 ctxt->context->node = NULL;
13223 /*
13224 * Only put the first node in the result, then leave.
13225 */
13226 if (newset->nodeNr > 0) {
13227 *first = *(newset->nodeTab);
13228 break;
13229 }
13230 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013231 if (tmp != NULL) {
13232 xmlXPathReleaseObject(ctxt->context, tmp);
13233 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013234 /*
13235 * The result is used as the new evaluation set.
13236 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013237 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013238 ctxt->context->node = NULL;
13239 ctxt->context->contextSize = -1;
13240 ctxt->context->proximityPosition = -1;
13241 /* may want to move this past the '}' later */
13242 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013243 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013244 }
13245 ctxt->context->node = oldnode;
13246 return(total);
13247}
13248#endif /* XP_OPTIMIZED_FILTER_FIRST */
13249
Owen Taylor3473f882001-02-23 17:55:21 +000013250/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013251 * xmlXPathCompOpEval:
13252 * @ctxt: the XPath parser context with the compiled expression
13253 * @op: an XPath compiled operation
13254 *
13255 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013256 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013257 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013258static int
13259xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13260{
13261 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013262 int equal, ret;
13263 xmlXPathCompExprPtr comp;
13264 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013265 xmlNodePtr bak;
13266 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013267 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013268 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013269
Daniel Veillard556c6682001-10-06 09:59:51 +000013270 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013271 comp = ctxt->comp;
13272 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013273 case XPATH_OP_END:
13274 return (0);
13275 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013276 bakd = ctxt->context->doc;
13277 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013278 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013279 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013280 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013281 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013282 xmlXPathBooleanFunction(ctxt, 1);
13283 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13284 return (total);
13285 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013286 ctxt->context->doc = bakd;
13287 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013288 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013289 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013290 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013291 if (ctxt->error) {
13292 xmlXPathFreeObject(arg2);
13293 return(0);
13294 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013295 xmlXPathBooleanFunction(ctxt, 1);
13296 arg1 = valuePop(ctxt);
13297 arg1->boolval &= arg2->boolval;
13298 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013299 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013300 return (total);
13301 case XPATH_OP_OR:
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 Veillardf06307e2001-07-03 10:35:50 +000013308 xmlXPathBooleanFunction(ctxt, 1);
13309 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13310 return (total);
13311 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013312 ctxt->context->doc = bakd;
13313 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013314 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013315 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013316 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013317 if (ctxt->error) {
13318 xmlXPathFreeObject(arg2);
13319 return(0);
13320 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013321 xmlXPathBooleanFunction(ctxt, 1);
13322 arg1 = valuePop(ctxt);
13323 arg1->boolval |= arg2->boolval;
13324 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013325 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013326 return (total);
13327 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013328 bakd = ctxt->context->doc;
13329 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013330 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013331 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013332 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013333 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013334 ctxt->context->doc = bakd;
13335 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013336 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013337 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013339 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013340 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013341 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013342 else
13343 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013344 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013345 return (total);
13346 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013347 bakd = ctxt->context->doc;
13348 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013349 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013350 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013351 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013352 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013353 ctxt->context->doc = bakd;
13354 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013355 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013356 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013357 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013358 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013359 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013360 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013361 return (total);
13362 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013363 bakd = ctxt->context->doc;
13364 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013365 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013366 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013367 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013368 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013369 if (op->ch2 != -1) {
13370 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 Veillard7089d6b2002-03-29 17:28:10 +000013375 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013376 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013377 if (op->value == 0)
13378 xmlXPathSubValues(ctxt);
13379 else if (op->value == 1)
13380 xmlXPathAddValues(ctxt);
13381 else if (op->value == 2)
13382 xmlXPathValueFlipSign(ctxt);
13383 else if (op->value == 3) {
13384 CAST_TO_NUMBER;
13385 CHECK_TYPE0(XPATH_NUMBER);
13386 }
13387 return (total);
13388 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013389 bakd = ctxt->context->doc;
13390 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013391 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013392 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013393 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013394 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013395 ctxt->context->doc = bakd;
13396 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013397 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013398 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013399 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013400 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013401 if (op->value == 0)
13402 xmlXPathMultValues(ctxt);
13403 else if (op->value == 1)
13404 xmlXPathDivValues(ctxt);
13405 else if (op->value == 2)
13406 xmlXPathModValues(ctxt);
13407 return (total);
13408 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013409 bakd = ctxt->context->doc;
13410 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013411 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013412 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013413 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013414 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013415 ctxt->context->doc = bakd;
13416 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013417 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013418 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013419 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013420 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013421 CHECK_TYPE0(XPATH_NODESET);
13422 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013423
Daniel Veillardf06307e2001-07-03 10:35:50 +000013424 CHECK_TYPE0(XPATH_NODESET);
13425 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013426
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013427 if ((arg1->nodesetval == NULL) ||
13428 ((arg2->nodesetval != NULL) &&
13429 (arg2->nodesetval->nodeNr != 0)))
13430 {
13431 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13432 arg2->nodesetval);
13433 }
13434
Daniel Veillardf06307e2001-07-03 10:35:50 +000013435 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013436 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013437 return (total);
13438 case XPATH_OP_ROOT:
13439 xmlXPathRoot(ctxt);
13440 return (total);
13441 case XPATH_OP_NODE:
13442 if (op->ch1 != -1)
13443 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013444 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013445 if (op->ch2 != -1)
13446 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013447 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013448 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13449 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013450 return (total);
13451 case XPATH_OP_RESET:
13452 if (op->ch1 != -1)
13453 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013454 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013455 if (op->ch2 != -1)
13456 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013457 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013458 ctxt->context->node = NULL;
13459 return (total);
13460 case XPATH_OP_COLLECT:{
13461 if (op->ch1 == -1)
13462 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013463
Daniel Veillardf06307e2001-07-03 10:35:50 +000013464 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013465 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013466
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013467 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013468 return (total);
13469 }
13470 case XPATH_OP_VALUE:
13471 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013472 xmlXPathCacheObjectCopy(ctxt->context,
13473 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013474 return (total);
13475 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013476 xmlXPathObjectPtr val;
13477
Daniel Veillardf06307e2001-07-03 10:35:50 +000013478 if (op->ch1 != -1)
13479 total +=
13480 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013481 if (op->value5 == NULL) {
13482 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13483 if (val == NULL) {
13484 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13485 return(0);
13486 }
13487 valuePush(ctxt, val);
13488 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013489 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013490
Daniel Veillardf06307e2001-07-03 10:35:50 +000013491 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13492 if (URI == NULL) {
13493 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013494 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13495 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013496 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013497 return (total);
13498 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013499 val = xmlXPathVariableLookupNS(ctxt->context,
13500 op->value4, URI);
13501 if (val == NULL) {
13502 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13503 return(0);
13504 }
13505 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013506 }
13507 return (total);
13508 }
13509 case XPATH_OP_FUNCTION:{
13510 xmlXPathFunction func;
13511 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013512 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013513 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013514
Daniel Veillardf5048b32011-08-18 17:10:13 +080013515 frame = xmlXPathSetFrame(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013516 if (op->ch1 != -1)
13517 total +=
13518 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013519 if (ctxt->valueNr < op->value) {
13520 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013521 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013522 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013523 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013524 return (total);
13525 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013526 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013527 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13528 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013529 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013530 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013531 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013532 return (total);
13533 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013534 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013535 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013536 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013537 else {
13538 const xmlChar *URI = NULL;
13539
13540 if (op->value5 == NULL)
13541 func =
13542 xmlXPathFunctionLookup(ctxt->context,
13543 op->value4);
13544 else {
13545 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13546 if (URI == NULL) {
13547 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013548 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13549 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013550 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013551 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013552 return (total);
13553 }
13554 func = xmlXPathFunctionLookupNS(ctxt->context,
13555 op->value4, URI);
13556 }
13557 if (func == NULL) {
13558 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013559 "xmlXPathCompOpEval: function %s not found\n",
13560 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013561 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013562 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013563 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013564 op->cacheURI = (void *) URI;
13565 }
13566 oldFunc = ctxt->context->function;
13567 oldFuncURI = ctxt->context->functionURI;
13568 ctxt->context->function = op->value4;
13569 ctxt->context->functionURI = op->cacheURI;
13570 func(ctxt, op->value);
13571 ctxt->context->function = oldFunc;
13572 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013573 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013574 return (total);
13575 }
13576 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013577 bakd = ctxt->context->doc;
13578 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013579 pp = ctxt->context->proximityPosition;
13580 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013581 if (op->ch1 != -1)
13582 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013583 ctxt->context->contextSize = cs;
13584 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013585 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013586 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013587 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013588 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013589 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013590 ctxt->context->doc = bakd;
13591 ctxt->context->node = bak;
13592 CHECK_ERROR0;
13593 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013594 return (total);
13595 case XPATH_OP_PREDICATE:
13596 case XPATH_OP_FILTER:{
13597 xmlXPathObjectPtr res;
13598 xmlXPathObjectPtr obj, tmp;
13599 xmlNodeSetPtr newset = NULL;
13600 xmlNodeSetPtr oldset;
13601 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013602 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013603 int i;
13604
13605 /*
13606 * Optimization for ()[1] selection i.e. the first elem
13607 */
13608 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013609#ifdef XP_OPTIMIZED_FILTER_FIRST
13610 /*
13611 * FILTER TODO: Can we assume that the inner processing
13612 * will result in an ordered list if we have an
13613 * XPATH_OP_FILTER?
13614 * What about an additional field or flag on
13615 * xmlXPathObject like @sorted ? This way we wouln'd need
13616 * to assume anything, so it would be more robust and
13617 * easier to optimize.
13618 */
13619 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13620 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13621#else
13622 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13623#endif
13624 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013625 xmlXPathObjectPtr val;
13626
13627 val = comp->steps[op->ch2].value4;
13628 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13629 (val->floatval == 1.0)) {
13630 xmlNodePtr first = NULL;
13631
13632 total +=
13633 xmlXPathCompOpEvalFirst(ctxt,
13634 &comp->steps[op->ch1],
13635 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013636 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013637 /*
13638 * The nodeset should be in document order,
13639 * Keep only the first value
13640 */
13641 if ((ctxt->value != NULL) &&
13642 (ctxt->value->type == XPATH_NODESET) &&
13643 (ctxt->value->nodesetval != NULL) &&
13644 (ctxt->value->nodesetval->nodeNr > 1))
13645 ctxt->value->nodesetval->nodeNr = 1;
13646 return (total);
13647 }
13648 }
13649 /*
13650 * Optimization for ()[last()] selection i.e. the last elem
13651 */
13652 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13653 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13654 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13655 int f = comp->steps[op->ch2].ch1;
13656
13657 if ((f != -1) &&
13658 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13659 (comp->steps[f].value5 == NULL) &&
13660 (comp->steps[f].value == 0) &&
13661 (comp->steps[f].value4 != NULL) &&
13662 (xmlStrEqual
13663 (comp->steps[f].value4, BAD_CAST "last"))) {
13664 xmlNodePtr last = NULL;
13665
13666 total +=
13667 xmlXPathCompOpEvalLast(ctxt,
13668 &comp->steps[op->ch1],
13669 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013670 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013671 /*
13672 * The nodeset should be in document order,
13673 * Keep only the last value
13674 */
13675 if ((ctxt->value != NULL) &&
13676 (ctxt->value->type == XPATH_NODESET) &&
13677 (ctxt->value->nodesetval != NULL) &&
13678 (ctxt->value->nodesetval->nodeTab != NULL) &&
13679 (ctxt->value->nodesetval->nodeNr > 1)) {
13680 ctxt->value->nodesetval->nodeTab[0] =
13681 ctxt->value->nodesetval->nodeTab[ctxt->
13682 value->
13683 nodesetval->
13684 nodeNr -
13685 1];
13686 ctxt->value->nodesetval->nodeNr = 1;
13687 }
13688 return (total);
13689 }
13690 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013691 /*
13692 * Process inner predicates first.
13693 * Example "index[parent::book][1]":
13694 * ...
13695 * PREDICATE <-- we are here "[1]"
13696 * PREDICATE <-- process "[parent::book]" first
13697 * SORT
13698 * COLLECT 'parent' 'name' 'node' book
13699 * NODE
13700 * ELEM Object is a number : 1
13701 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013702 if (op->ch1 != -1)
13703 total +=
13704 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013705 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013706 if (op->ch2 == -1)
13707 return (total);
13708 if (ctxt->value == NULL)
13709 return (total);
13710
13711 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013712
13713#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013714 /*
13715 * Hum are we filtering the result of an XPointer expression
13716 */
13717 if (ctxt->value->type == XPATH_LOCATIONSET) {
13718 xmlLocationSetPtr newlocset = NULL;
13719 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013720
Daniel Veillardf06307e2001-07-03 10:35:50 +000013721 /*
13722 * Extract the old locset, and then evaluate the result of the
13723 * expression for all the element in the locset. use it to grow
13724 * up a new locset.
13725 */
13726 CHECK_TYPE0(XPATH_LOCATIONSET);
13727 obj = valuePop(ctxt);
13728 oldlocset = obj->user;
13729 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013730
Daniel Veillardf06307e2001-07-03 10:35:50 +000013731 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13732 ctxt->context->contextSize = 0;
13733 ctxt->context->proximityPosition = 0;
13734 if (op->ch2 != -1)
13735 total +=
13736 xmlXPathCompOpEval(ctxt,
13737 &comp->steps[op->ch2]);
13738 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013739 if (res != NULL) {
13740 xmlXPathReleaseObject(ctxt->context, res);
13741 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013742 valuePush(ctxt, obj);
13743 CHECK_ERROR0;
13744 return (total);
13745 }
13746 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013747
Daniel Veillardf06307e2001-07-03 10:35:50 +000013748 for (i = 0; i < oldlocset->locNr; i++) {
13749 /*
13750 * Run the evaluation with a node list made of a
13751 * single item in the nodelocset.
13752 */
13753 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013754 ctxt->context->contextSize = oldlocset->locNr;
13755 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013756 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13757 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013758 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013759
Daniel Veillardf06307e2001-07-03 10:35:50 +000013760 if (op->ch2 != -1)
13761 total +=
13762 xmlXPathCompOpEval(ctxt,
13763 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013764 if (ctxt->error != XPATH_EXPRESSION_OK) {
13765 xmlXPathFreeObject(obj);
13766 return(0);
13767 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013768
Daniel Veillardf06307e2001-07-03 10:35:50 +000013769 /*
13770 * The result of the evaluation need to be tested to
13771 * decided whether the filter succeeded or not
13772 */
13773 res = valuePop(ctxt);
13774 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13775 xmlXPtrLocationSetAdd(newlocset,
13776 xmlXPathObjectCopy
13777 (oldlocset->locTab[i]));
13778 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013779
Daniel Veillardf06307e2001-07-03 10:35:50 +000013780 /*
13781 * Cleanup
13782 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013783 if (res != NULL) {
13784 xmlXPathReleaseObject(ctxt->context, res);
13785 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013786 if (ctxt->value == tmp) {
13787 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013788 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013789 }
13790
13791 ctxt->context->node = NULL;
13792 }
13793
13794 /*
13795 * The result is used as the new evaluation locset.
13796 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013797 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013798 ctxt->context->node = NULL;
13799 ctxt->context->contextSize = -1;
13800 ctxt->context->proximityPosition = -1;
13801 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13802 ctxt->context->node = oldnode;
13803 return (total);
13804 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013805#endif /* LIBXML_XPTR_ENABLED */
13806
Daniel Veillardf06307e2001-07-03 10:35:50 +000013807 /*
13808 * Extract the old set, and then evaluate the result of the
13809 * expression for all the element in the set. use it to grow
13810 * up a new set.
13811 */
13812 CHECK_TYPE0(XPATH_NODESET);
13813 obj = valuePop(ctxt);
13814 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013815
Daniel Veillardf06307e2001-07-03 10:35:50 +000013816 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013817 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013818 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013819
Daniel Veillardf06307e2001-07-03 10:35:50 +000013820 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13821 ctxt->context->contextSize = 0;
13822 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013823/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013824 if (op->ch2 != -1)
13825 total +=
13826 xmlXPathCompOpEval(ctxt,
13827 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013828 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013829 res = valuePop(ctxt);
13830 if (res != NULL)
13831 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013832*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013833 valuePush(ctxt, obj);
13834 ctxt->context->node = oldnode;
13835 CHECK_ERROR0;
13836 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013837 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013838 /*
13839 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013840 * Also set the xpath document in case things like
13841 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013842 */
13843 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013844 /*
13845 * SPEC XPath 1.0:
13846 * "For each node in the node-set to be filtered, the
13847 * PredicateExpr is evaluated with that node as the
13848 * context node, with the number of nodes in the
13849 * node-set as the context size, and with the proximity
13850 * position of the node in the node-set with respect to
13851 * the axis as the context position;"
13852 * @oldset is the node-set" to be filtered.
13853 *
13854 * SPEC XPath 1.0:
13855 * "only predicates change the context position and
13856 * context size (see [2.4 Predicates])."
13857 * Example:
13858 * node-set context pos
13859 * nA 1
13860 * nB 2
13861 * nC 3
13862 * After applying predicate [position() > 1] :
13863 * node-set context pos
13864 * nB 1
13865 * nC 2
13866 *
13867 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013868 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013869 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013870 for (i = 0; i < oldset->nodeNr; i++) {
13871 /*
13872 * Run the evaluation with a node list made of
13873 * a single item in the nodeset.
13874 */
13875 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013876 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13877 (oldset->nodeTab[i]->doc != NULL))
13878 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013879 if (tmp == NULL) {
13880 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13881 ctxt->context->node);
13882 } else {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013883 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13884 ctxt->context->node) < 0) {
13885 ctxt->error = XPATH_MEMORY_ERROR;
13886 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013887 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013888 valuePush(ctxt, tmp);
13889 ctxt->context->contextSize = oldset->nodeNr;
13890 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013891 /*
13892 * Evaluate the predicate against the context node.
13893 * Can/should we optimize position() predicates
13894 * here (e.g. "[1]")?
13895 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013896 if (op->ch2 != -1)
13897 total +=
13898 xmlXPathCompOpEval(ctxt,
13899 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013900 if (ctxt->error != XPATH_EXPRESSION_OK) {
13901 xmlXPathFreeNodeSet(newset);
13902 xmlXPathFreeObject(obj);
13903 return(0);
13904 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013905
Daniel Veillardf06307e2001-07-03 10:35:50 +000013906 /*
William M. Brack08171912003-12-29 02:52:11 +000013907 * The result of the evaluation needs to be tested to
13908 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013909 */
13910 /*
13911 * OPTIMIZE TODO: Can we use
13912 * xmlXPathNodeSetAdd*Unique()* instead?
13913 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013914 res = valuePop(ctxt);
13915 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard1bd45d12012-09-05 15:35:19 +080013916 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13917 < 0)
13918 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013919 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013920
Daniel Veillardf06307e2001-07-03 10:35:50 +000013921 /*
13922 * Cleanup
13923 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013924 if (res != NULL) {
13925 xmlXPathReleaseObject(ctxt->context, res);
13926 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013927 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013928 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013929 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013930 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013931 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013932 * in order to avoid massive recreation inside this
13933 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013934 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013935 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013936 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013937 ctxt->context->node = NULL;
13938 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013939 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013940 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013941 /*
13942 * The result is used as the new evaluation set.
13943 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013944 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013945 ctxt->context->node = NULL;
13946 ctxt->context->contextSize = -1;
13947 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013948 /* may want to move this past the '}' later */
13949 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013950 valuePush(ctxt,
13951 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013952 }
13953 ctxt->context->node = oldnode;
13954 return (total);
13955 }
13956 case XPATH_OP_SORT:
13957 if (op->ch1 != -1)
13958 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013959 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013960 if ((ctxt->value != NULL) &&
13961 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013962 (ctxt->value->nodesetval != NULL) &&
13963 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013964 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013965 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013966 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013967 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013968#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013969 case XPATH_OP_RANGETO:{
13970 xmlXPathObjectPtr range;
13971 xmlXPathObjectPtr res, obj;
13972 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013973 xmlLocationSetPtr newlocset = NULL;
13974 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013975 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013976 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013977
Daniel Veillardf06307e2001-07-03 10:35:50 +000013978 if (op->ch1 != -1)
13979 total +=
13980 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13981 if (op->ch2 == -1)
13982 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013983
William M. Brack08171912003-12-29 02:52:11 +000013984 if (ctxt->value->type == XPATH_LOCATIONSET) {
13985 /*
13986 * Extract the old locset, and then evaluate the result of the
13987 * expression for all the element in the locset. use it to grow
13988 * up a new locset.
13989 */
13990 CHECK_TYPE0(XPATH_LOCATIONSET);
13991 obj = valuePop(ctxt);
13992 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013993
William M. Brack08171912003-12-29 02:52:11 +000013994 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013995 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013996 ctxt->context->contextSize = 0;
13997 ctxt->context->proximityPosition = 0;
13998 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13999 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014000 if (res != NULL) {
14001 xmlXPathReleaseObject(ctxt->context, res);
14002 }
William M. Brack08171912003-12-29 02:52:11 +000014003 valuePush(ctxt, obj);
14004 CHECK_ERROR0;
14005 return (total);
14006 }
14007 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014008
William M. Brack08171912003-12-29 02:52:11 +000014009 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000014010 /*
William M. Brack08171912003-12-29 02:52:11 +000014011 * Run the evaluation with a node list made of a
14012 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000014013 */
William M. Brackf7eb7942003-12-31 07:59:17 +000014014 ctxt->context->node = oldlocset->locTab[i]->user;
14015 ctxt->context->contextSize = oldlocset->locNr;
14016 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014017 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14018 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014019 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014020
Daniel Veillardf06307e2001-07-03 10:35:50 +000014021 if (op->ch2 != -1)
14022 total +=
14023 xmlXPathCompOpEval(ctxt,
14024 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014025 if (ctxt->error != XPATH_EXPRESSION_OK) {
14026 xmlXPathFreeObject(obj);
14027 return(0);
14028 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014029
Daniel Veillardf06307e2001-07-03 10:35:50 +000014030 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000014031 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014032 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000014033 (xmlLocationSetPtr)res->user;
14034 for (j=0; j<rloc->locNr; j++) {
14035 range = xmlXPtrNewRange(
14036 oldlocset->locTab[i]->user,
14037 oldlocset->locTab[i]->index,
14038 rloc->locTab[j]->user2,
14039 rloc->locTab[j]->index2);
14040 if (range != NULL) {
14041 xmlXPtrLocationSetAdd(newlocset, range);
14042 }
14043 }
14044 } else {
14045 range = xmlXPtrNewRangeNodeObject(
14046 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14047 if (range != NULL) {
14048 xmlXPtrLocationSetAdd(newlocset,range);
14049 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014050 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014051
Daniel Veillardf06307e2001-07-03 10:35:50 +000014052 /*
14053 * Cleanup
14054 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014055 if (res != NULL) {
14056 xmlXPathReleaseObject(ctxt->context, res);
14057 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014058 if (ctxt->value == tmp) {
14059 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014060 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014061 }
14062
14063 ctxt->context->node = NULL;
14064 }
William M. Brack72ee48d2003-12-30 08:30:19 +000014065 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000014066 CHECK_TYPE0(XPATH_NODESET);
14067 obj = valuePop(ctxt);
14068 oldset = obj->nodesetval;
14069 ctxt->context->node = NULL;
14070
14071 newlocset = xmlXPtrLocationSetCreate(NULL);
14072
14073 if (oldset != NULL) {
14074 for (i = 0; i < oldset->nodeNr; i++) {
14075 /*
14076 * Run the evaluation with a node list made of a single item
14077 * in the nodeset.
14078 */
14079 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014080 /*
14081 * OPTIMIZE TODO: Avoid recreation for every iteration.
14082 */
14083 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14084 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000014085 valuePush(ctxt, tmp);
14086
14087 if (op->ch2 != -1)
14088 total +=
14089 xmlXPathCompOpEval(ctxt,
14090 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014091 if (ctxt->error != XPATH_EXPRESSION_OK) {
14092 xmlXPathFreeObject(obj);
14093 return(0);
14094 }
William M. Brack08171912003-12-29 02:52:11 +000014095
William M. Brack08171912003-12-29 02:52:11 +000014096 res = valuePop(ctxt);
14097 range =
14098 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14099 res);
14100 if (range != NULL) {
14101 xmlXPtrLocationSetAdd(newlocset, range);
14102 }
14103
14104 /*
14105 * Cleanup
14106 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014107 if (res != NULL) {
14108 xmlXPathReleaseObject(ctxt->context, res);
14109 }
William M. Brack08171912003-12-29 02:52:11 +000014110 if (ctxt->value == tmp) {
14111 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014112 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000014113 }
14114
14115 ctxt->context->node = NULL;
14116 }
14117 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014118 }
14119
14120 /*
14121 * The result is used as the new evaluation set.
14122 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014123 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014124 ctxt->context->node = NULL;
14125 ctxt->context->contextSize = -1;
14126 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000014127 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014128 return (total);
14129 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014130#endif /* LIBXML_XPTR_ENABLED */
14131 }
14132 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000014133 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080014134 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014135 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014136}
14137
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014138/**
14139 * xmlXPathCompOpEvalToBoolean:
14140 * @ctxt: the XPath parser context
14141 *
14142 * Evaluates if the expression evaluates to true.
14143 *
14144 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14145 */
14146static int
14147xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014148 xmlXPathStepOpPtr op,
14149 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014150{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014151 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014152
14153start:
14154 /* comp = ctxt->comp; */
14155 switch (op->op) {
14156 case XPATH_OP_END:
14157 return (0);
14158 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014159 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014160 if (isPredicate)
14161 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14162 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014163 case XPATH_OP_SORT:
14164 /*
14165 * We don't need sorting for boolean results. Skip this one.
14166 */
14167 if (op->ch1 != -1) {
14168 op = &ctxt->comp->steps[op->ch1];
14169 goto start;
14170 }
14171 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014172 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014173 if (op->ch1 == -1)
14174 return(0);
14175
14176 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14177 if (ctxt->error != XPATH_EXPRESSION_OK)
14178 return(-1);
14179
14180 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14181 if (ctxt->error != XPATH_EXPRESSION_OK)
14182 return(-1);
14183
14184 resObj = valuePop(ctxt);
14185 if (resObj == NULL)
14186 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014187 break;
14188 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014189 /*
14190 * Fallback to call xmlXPathCompOpEval().
14191 */
14192 xmlXPathCompOpEval(ctxt, op);
14193 if (ctxt->error != XPATH_EXPRESSION_OK)
14194 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014195
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014196 resObj = valuePop(ctxt);
14197 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014198 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014199 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014200 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014201
14202 if (resObj) {
14203 int res;
14204
14205 if (resObj->type == XPATH_BOOLEAN) {
14206 res = resObj->boolval;
14207 } else if (isPredicate) {
14208 /*
14209 * For predicates a result of type "number" is handled
14210 * differently:
14211 * SPEC XPath 1.0:
14212 * "If the result is a number, the result will be converted
14213 * to true if the number is equal to the context position
14214 * and will be converted to false otherwise;"
14215 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014216 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014217 } else {
14218 res = xmlXPathCastToBoolean(resObj);
14219 }
14220 xmlXPathReleaseObject(ctxt->context, resObj);
14221 return(res);
14222 }
14223
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014224 return(0);
14225}
14226
Daniel Veillard56de87e2005-02-16 00:22:29 +000014227#ifdef XPATH_STREAMING
14228/**
14229 * xmlXPathRunStreamEval:
14230 * @ctxt: the XPath parser context with the compiled expression
14231 *
14232 * Evaluate the Precompiled Streamable XPath expression in the given context.
14233 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014234static int
14235xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14236 xmlXPathObjectPtr *resultSeq, int toBool)
14237{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014238 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014239 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014240 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014241 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014242 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014243 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014244
14245 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014246
14247 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014248 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014249 max_depth = xmlPatternMaxDepth(comp);
14250 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014251 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014252 if (max_depth == -2)
14253 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014254 min_depth = xmlPatternMinDepth(comp);
14255 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014256 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014257 from_root = xmlPatternFromRoot(comp);
14258 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014259 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014260#if 0
14261 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14262#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014263
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014264 if (! toBool) {
14265 if (resultSeq == NULL)
14266 return(-1);
14267 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14268 if (*resultSeq == NULL)
14269 return(-1);
14270 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014271
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014272 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014273 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014274 */
14275 if (min_depth == 0) {
14276 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014277 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014278 if (toBool)
14279 return(1);
14280 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014281 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014282 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014283 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014284 if (toBool)
14285 return(1);
14286 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014287 }
14288 }
14289 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014290 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014291 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014292
Daniel Veillard56de87e2005-02-16 00:22:29 +000014293 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014294 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014295 } else if (ctxt->node != NULL) {
14296 switch (ctxt->node->type) {
14297 case XML_ELEMENT_NODE:
14298 case XML_DOCUMENT_NODE:
14299 case XML_DOCUMENT_FRAG_NODE:
14300 case XML_HTML_DOCUMENT_NODE:
14301#ifdef LIBXML_DOCB_ENABLED
14302 case XML_DOCB_DOCUMENT_NODE:
14303#endif
14304 cur = ctxt->node;
14305 break;
14306 case XML_ATTRIBUTE_NODE:
14307 case XML_TEXT_NODE:
14308 case XML_CDATA_SECTION_NODE:
14309 case XML_ENTITY_REF_NODE:
14310 case XML_ENTITY_NODE:
14311 case XML_PI_NODE:
14312 case XML_COMMENT_NODE:
14313 case XML_NOTATION_NODE:
14314 case XML_DTD_NODE:
14315 case XML_DOCUMENT_TYPE_NODE:
14316 case XML_ELEMENT_DECL:
14317 case XML_ATTRIBUTE_DECL:
14318 case XML_ENTITY_DECL:
14319 case XML_NAMESPACE_DECL:
14320 case XML_XINCLUDE_START:
14321 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014322 break;
14323 }
14324 limit = cur;
14325 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014326 if (cur == NULL) {
14327 return(0);
14328 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014329
14330 patstream = xmlPatternGetStreamCtxt(comp);
14331 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014332 /*
14333 * QUESTION TODO: Is this an error?
14334 */
14335 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014336 }
14337
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014338 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014339
Daniel Veillard56de87e2005-02-16 00:22:29 +000014340 if (from_root) {
14341 ret = xmlStreamPush(patstream, NULL, NULL);
14342 if (ret < 0) {
14343 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014344 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014345 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014346 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014347 }
14348 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014349 depth = 0;
14350 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014351next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014352 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014353 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014354
14355 switch (cur->type) {
14356 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014357 case XML_TEXT_NODE:
14358 case XML_CDATA_SECTION_NODE:
14359 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014360 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014361 if (cur->type == XML_ELEMENT_NODE) {
14362 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014363 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014364 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014365 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14366 else
14367 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014368
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014369 if (ret < 0) {
14370 /* NOP. */
14371 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014372 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014373 goto return_1;
Daniel Veillard1bd45d12012-09-05 15:35:19 +080014374 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14375 < 0) {
14376 ctxt->lastError.domain = XML_FROM_XPATH;
14377 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14378 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014379 }
14380 if ((cur->children == NULL) || (depth >= max_depth)) {
14381 ret = xmlStreamPop(patstream);
14382 while (cur->next != NULL) {
14383 cur = cur->next;
14384 if ((cur->type != XML_ENTITY_DECL) &&
14385 (cur->type != XML_DTD_NODE))
14386 goto next_node;
14387 }
14388 }
14389 default:
14390 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014391 }
14392
Daniel Veillard56de87e2005-02-16 00:22:29 +000014393scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080014394 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014395 if ((cur->children != NULL) && (depth < max_depth)) {
14396 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014397 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014398 */
14399 if (cur->children->type != XML_ENTITY_DECL) {
14400 cur = cur->children;
14401 depth++;
14402 /*
14403 * Skip DTDs
14404 */
14405 if (cur->type != XML_DTD_NODE)
14406 continue;
14407 }
14408 }
14409
14410 if (cur == limit)
14411 break;
14412
14413 while (cur->next != NULL) {
14414 cur = cur->next;
14415 if ((cur->type != XML_ENTITY_DECL) &&
14416 (cur->type != XML_DTD_NODE))
14417 goto next_node;
14418 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014419
Daniel Veillard56de87e2005-02-16 00:22:29 +000014420 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014421 cur = cur->parent;
14422 depth--;
14423 if ((cur == NULL) || (cur == limit))
14424 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014425 if (cur->type == XML_ELEMENT_NODE) {
14426 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014427 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014428 ((cur->type == XML_TEXT_NODE) ||
14429 (cur->type == XML_CDATA_SECTION_NODE) ||
14430 (cur->type == XML_COMMENT_NODE) ||
14431 (cur->type == XML_PI_NODE)))
14432 {
14433 ret = xmlStreamPop(patstream);
14434 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014435 if (cur->next != NULL) {
14436 cur = cur->next;
14437 break;
14438 }
14439 } while (cur != NULL);
14440
14441 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014442
Daniel Veillard56de87e2005-02-16 00:22:29 +000014443done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014444
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014445#if 0
14446 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014447 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014448#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014449
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014450 if (patstream)
14451 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014452 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014453
14454return_1:
14455 if (patstream)
14456 xmlFreeStreamCtxt(patstream);
14457 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014458}
14459#endif /* XPATH_STREAMING */
14460
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014461/**
14462 * xmlXPathRunEval:
14463 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014464 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014465 *
14466 * Evaluate the Precompiled XPath expression in the given context.
14467 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014468static int
14469xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14470{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014471 xmlXPathCompExprPtr comp;
14472
14473 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014474 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014475
14476 if (ctxt->valueTab == NULL) {
14477 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014478 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014479 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14480 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014481 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014482 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014483 }
14484 ctxt->valueNr = 0;
14485 ctxt->valueMax = 10;
14486 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014487 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014488 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014489#ifdef XPATH_STREAMING
14490 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014491 int res;
14492
14493 if (toBool) {
14494 /*
14495 * Evaluation to boolean result.
14496 */
14497 res = xmlXPathRunStreamEval(ctxt->context,
14498 ctxt->comp->stream, NULL, 1);
14499 if (res != -1)
14500 return(res);
14501 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014502 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014503
14504 /*
14505 * Evaluation to a sequence.
14506 */
14507 res = xmlXPathRunStreamEval(ctxt->context,
14508 ctxt->comp->stream, &resObj, 0);
14509
14510 if ((res != -1) && (resObj != NULL)) {
14511 valuePush(ctxt, resObj);
14512 return(0);
14513 }
14514 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014515 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014516 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014517 /*
14518 * QUESTION TODO: This falls back to normal XPath evaluation
14519 * if res == -1. Is this intended?
14520 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014521 }
14522#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014523 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014524 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014525 xmlGenericError(xmlGenericErrorContext,
14526 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014527 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014528 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014529 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014530 return(xmlXPathCompOpEvalToBoolean(ctxt,
14531 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014532 else
14533 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14534
14535 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014536}
14537
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014538/************************************************************************
14539 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014540 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014541 * *
14542 ************************************************************************/
14543
14544/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014545 * xmlXPathEvalPredicate:
14546 * @ctxt: the XPath context
14547 * @res: the Predicate Expression evaluation result
14548 *
14549 * Evaluate a predicate result for the current node.
14550 * A PredicateExpr is evaluated by evaluating the Expr and converting
14551 * the result to a boolean. If the result is a number, the result will
14552 * be converted to true if the number is equal to the position of the
14553 * context node in the context node list (as returned by the position
14554 * function) and will be converted to false otherwise; if the result
14555 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014556 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014557 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014558 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014559 */
14560int
14561xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014562 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014563 switch (res->type) {
14564 case XPATH_BOOLEAN:
14565 return(res->boolval);
14566 case XPATH_NUMBER:
14567 return(res->floatval == ctxt->proximityPosition);
14568 case XPATH_NODESET:
14569 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014570 if (res->nodesetval == NULL)
14571 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014572 return(res->nodesetval->nodeNr != 0);
14573 case XPATH_STRING:
14574 return((res->stringval != NULL) &&
14575 (xmlStrlen(res->stringval) != 0));
14576 default:
14577 STRANGE
14578 }
14579 return(0);
14580}
14581
14582/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014583 * xmlXPathEvaluatePredicateResult:
14584 * @ctxt: the XPath Parser context
14585 * @res: the Predicate Expression evaluation result
14586 *
14587 * Evaluate a predicate result for the current node.
14588 * A PredicateExpr is evaluated by evaluating the Expr and converting
14589 * the result to a boolean. If the result is a number, the result will
14590 * be converted to true if the number is equal to the position of the
14591 * context node in the context node list (as returned by the position
14592 * function) and will be converted to false otherwise; if the result
14593 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014594 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014595 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014596 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014597 */
14598int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014599xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014600 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014601 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014602 switch (res->type) {
14603 case XPATH_BOOLEAN:
14604 return(res->boolval);
14605 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014606#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014607 return((res->floatval == ctxt->context->proximityPosition) &&
14608 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014609#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014610 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014611#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014612 case XPATH_NODESET:
14613 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014614 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014615 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014616 return(res->nodesetval->nodeNr != 0);
14617 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014618 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014619#ifdef LIBXML_XPTR_ENABLED
14620 case XPATH_LOCATIONSET:{
14621 xmlLocationSetPtr ptr = res->user;
14622 if (ptr == NULL)
14623 return(0);
14624 return (ptr->locNr != 0);
14625 }
14626#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014627 default:
14628 STRANGE
14629 }
14630 return(0);
14631}
14632
Daniel Veillard56de87e2005-02-16 00:22:29 +000014633#ifdef XPATH_STREAMING
14634/**
14635 * xmlXPathTryStreamCompile:
14636 * @ctxt: an XPath context
14637 * @str: the XPath expression
14638 *
14639 * Try to compile the XPath expression as a streamable subset.
14640 *
14641 * Returns the compiled expression or NULL if failed to compile.
14642 */
14643static xmlXPathCompExprPtr
14644xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14645 /*
14646 * Optimization: use streaming patterns when the XPath expression can
14647 * be compiled to a stream lookup
14648 */
14649 xmlPatternPtr stream;
14650 xmlXPathCompExprPtr comp;
14651 xmlDictPtr dict = NULL;
14652 const xmlChar **namespaces = NULL;
14653 xmlNsPtr ns;
14654 int i, j;
14655
14656 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14657 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014658 const xmlChar *tmp;
14659
14660 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014661 * We don't try to handle expressions using the verbose axis
14662 * specifiers ("::"), just the simplied form at this point.
14663 * Additionally, if there is no list of namespaces available and
14664 * there's a ":" in the expression, indicating a prefixed QName,
14665 * then we won't try to compile either. xmlPatterncompile() needs
14666 * to have a list of namespaces at compilation time in order to
14667 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014668 */
14669 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014670 if ((tmp != NULL) &&
14671 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014672 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014673
Daniel Veillard56de87e2005-02-16 00:22:29 +000014674 if (ctxt != NULL) {
14675 dict = ctxt->dict;
14676 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014677 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014678 if (namespaces == NULL) {
14679 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14680 return(NULL);
14681 }
14682 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14683 ns = ctxt->namespaces[j];
14684 namespaces[i++] = ns->href;
14685 namespaces[i++] = ns->prefix;
14686 }
14687 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014688 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014689 }
14690 }
14691
William M. Brackea152c02005-06-09 18:12:28 +000014692 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14693 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014694 if (namespaces != NULL) {
14695 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014696 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014697 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14698 comp = xmlXPathNewCompExpr();
14699 if (comp == NULL) {
14700 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14701 return(NULL);
14702 }
14703 comp->stream = stream;
14704 comp->dict = dict;
14705 if (comp->dict)
14706 xmlDictReference(comp->dict);
14707 return(comp);
14708 }
14709 xmlFreePattern(stream);
14710 }
14711 return(NULL);
14712}
14713#endif /* XPATH_STREAMING */
14714
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014715static void
Nick Wellnhofer62270532012-08-19 19:42:38 +020014716xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014717{
14718 /*
14719 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14720 * internal representation.
14721 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014722
Nick Wellnhofer62270532012-08-19 19:42:38 +020014723 if ((op->ch1 != -1) &&
14724 (op->op == XPATH_OP_COLLECT /* 11 */))
14725 {
14726 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14727
14728 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14729 ((xmlXPathAxisVal) prevop->value ==
14730 AXIS_DESCENDANT_OR_SELF) &&
14731 (prevop->ch2 == -1) &&
14732 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14733 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14734 {
14735 /*
14736 * This is a "descendant-or-self::node()" without predicates.
14737 * Try to eliminate it.
14738 */
14739
14740 switch ((xmlXPathAxisVal) op->value) {
14741 case AXIS_CHILD:
14742 case AXIS_DESCENDANT:
14743 /*
14744 * Convert "descendant-or-self::node()/child::" or
14745 * "descendant-or-self::node()/descendant::" to
14746 * "descendant::"
14747 */
14748 op->ch1 = prevop->ch1;
14749 op->value = AXIS_DESCENDANT;
14750 break;
14751 case AXIS_SELF:
14752 case AXIS_DESCENDANT_OR_SELF:
14753 /*
14754 * Convert "descendant-or-self::node()/self::" or
14755 * "descendant-or-self::node()/descendant-or-self::" to
14756 * to "descendant-or-self::"
14757 */
14758 op->ch1 = prevop->ch1;
14759 op->value = AXIS_DESCENDANT_OR_SELF;
14760 break;
14761 default:
14762 break;
14763 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014764 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014765 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014766
14767 /* Recurse */
14768 if (op->ch1 != -1)
14769 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014770 if (op->ch2 != -1)
Nick Wellnhofer62270532012-08-19 19:42:38 +020014771 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014772}
14773
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014774/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014775 * xmlXPathCtxtCompile:
14776 * @ctxt: an XPath context
14777 * @str: the XPath expression
14778 *
14779 * Compile an XPath expression
14780 *
14781 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14782 * the caller has to free the object.
14783 */
14784xmlXPathCompExprPtr
14785xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14786 xmlXPathParserContextPtr pctxt;
14787 xmlXPathCompExprPtr comp;
14788
Daniel Veillard56de87e2005-02-16 00:22:29 +000014789#ifdef XPATH_STREAMING
14790 comp = xmlXPathTryStreamCompile(ctxt, str);
14791 if (comp != NULL)
14792 return(comp);
14793#endif
14794
Daniel Veillard4773df22004-01-23 13:15:13 +000014795 xmlXPathInit();
14796
14797 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014798 if (pctxt == NULL)
14799 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014800 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014801
14802 if( pctxt->error != XPATH_EXPRESSION_OK )
14803 {
14804 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014805 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014806 }
14807
14808 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014809 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014810 * aleksey: in some cases this line prints *second* error message
14811 * (see bug #78858) and probably this should be fixed.
14812 * However, we are not sure that all error messages are printed
14813 * out in other places. It's not critical so we leave it as-is for now
14814 */
14815 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14816 comp = NULL;
14817 } else {
14818 comp = pctxt->comp;
14819 pctxt->comp = NULL;
14820 }
14821 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014822
Daniel Veillard4773df22004-01-23 13:15:13 +000014823 if (comp != NULL) {
14824 comp->expr = xmlStrdup(str);
14825#ifdef DEBUG_EVAL_COUNTS
14826 comp->string = xmlStrdup(str);
14827 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014828#endif
Nick Wellnhofer62270532012-08-19 19:42:38 +020014829 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14830 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014831 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014832 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014833 return(comp);
14834}
14835
14836/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014837 * xmlXPathCompile:
14838 * @str: the XPath expression
14839 *
14840 * Compile an XPath expression
14841 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014842 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014843 * the caller has to free the object.
14844 */
14845xmlXPathCompExprPtr
14846xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014847 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014848}
14849
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014850/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014851 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014852 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014853 * @ctxt: the XPath context
14854 * @resObj: the resulting XPath object or NULL
14855 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014856 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014857 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014858 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014859 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014860 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014861 * the caller has to free the object.
14862 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014863static int
14864xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14865 xmlXPathContextPtr ctxt,
14866 xmlXPathObjectPtr *resObj,
14867 int toBool)
14868{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014869 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014870#ifndef LIBXML_THREAD_ENABLED
14871 static int reentance = 0;
14872#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014873 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014874
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014875 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014876
14877 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014878 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014879 xmlXPathInit();
14880
Daniel Veillard81463942001-10-16 12:34:39 +000014881#ifndef LIBXML_THREAD_ENABLED
14882 reentance++;
14883 if (reentance > 1)
14884 xmlXPathDisableOptimizer = 1;
14885#endif
14886
Daniel Veillardf06307e2001-07-03 10:35:50 +000014887#ifdef DEBUG_EVAL_COUNTS
14888 comp->nb++;
14889 if ((comp->string != NULL) && (comp->nb > 100)) {
14890 fprintf(stderr, "100 x %s\n", comp->string);
14891 comp->nb = 0;
14892 }
14893#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014894 pctxt = xmlXPathCompParserContext(comp, ctxt);
14895 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014896
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014897 if (resObj) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014898 if (pctxt->value == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014899 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014900 "xmlXPathCompiledEval: evaluation failed\n");
Daniel Veillard45490ae2008-07-29 09:13:19 +000014901 *resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014902 } else {
14903 *resObj = valuePop(pctxt);
14904 }
Owen Taylor3473f882001-02-23 17:55:21 +000014905 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014906
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014907 /*
14908 * Pop all remaining objects from the stack.
14909 */
14910 if (pctxt->valueNr > 0) {
14911 xmlXPathObjectPtr tmp;
14912 int stack = 0;
14913
14914 do {
14915 tmp = valuePop(pctxt);
14916 if (tmp != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014917 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014918 xmlXPathReleaseObject(ctxt, tmp);
14919 }
14920 } while (tmp != NULL);
14921 if ((stack != 0) &&
14922 ((toBool) || ((resObj) && (*resObj))))
14923 {
14924 xmlGenericError(xmlGenericErrorContext,
14925 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14926 stack);
14927 }
Owen Taylor3473f882001-02-23 17:55:21 +000014928 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014929
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014930 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14931 xmlXPathFreeObject(*resObj);
14932 *resObj = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014933 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014934 pctxt->comp = NULL;
14935 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014936#ifndef LIBXML_THREAD_ENABLED
14937 reentance--;
14938#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014939
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014940 return(res);
14941}
14942
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014943/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014944 * xmlXPathCompiledEval:
14945 * @comp: the compiled XPath expression
14946 * @ctx: the XPath context
14947 *
14948 * Evaluate the Precompiled XPath expression in the given context.
14949 *
14950 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14951 * the caller has to free the object.
14952 */
14953xmlXPathObjectPtr
14954xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14955{
14956 xmlXPathObjectPtr res = NULL;
14957
14958 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14959 return(res);
14960}
14961
14962/**
14963 * xmlXPathCompiledEvalToBoolean:
14964 * @comp: the compiled XPath expression
14965 * @ctxt: the XPath context
14966 *
14967 * Applies the XPath boolean() function on the result of the given
14968 * compiled expression.
14969 *
14970 * Returns 1 if the expression evaluated to true, 0 if to false and
14971 * -1 in API and internal errors.
14972 */
14973int
14974xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14975 xmlXPathContextPtr ctxt)
14976{
14977 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14978}
14979
14980/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014981 * xmlXPathEvalExpr:
14982 * @ctxt: the XPath Parser context
14983 *
14984 * Parse and evaluate an XPath expression in the given context,
14985 * then push the result on the context stack
14986 */
14987void
14988xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014989#ifdef XPATH_STREAMING
14990 xmlXPathCompExprPtr comp;
14991#endif
14992
Daniel Veillarda82b1822004-11-08 16:24:57 +000014993 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014994
Daniel Veillard56de87e2005-02-16 00:22:29 +000014995#ifdef XPATH_STREAMING
14996 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14997 if (comp != NULL) {
14998 if (ctxt->comp != NULL)
14999 xmlXPathFreeCompExpr(ctxt->comp);
15000 ctxt->comp = comp;
15001 if (ctxt->cur != NULL)
15002 while (*ctxt->cur != 0) ctxt->cur++;
15003 } else
15004#endif
15005 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000015006 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000015007 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
15008 (ctxt->comp != NULL) &&
Nick Wellnhofer62270532012-08-19 19:42:38 +020015009 (ctxt->comp->nbStep > 1) &&
15010 (ctxt->comp->last >= 0))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000015011 {
Nick Wellnhofer62270532012-08-19 19:42:38 +020015012 xmlXPathOptimizeExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000015013 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000015014 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000015015 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000015016 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015017 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000015018}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015019
15020/**
15021 * xmlXPathEval:
15022 * @str: the XPath expression
15023 * @ctx: the XPath context
15024 *
15025 * Evaluate the XPath Location Path in the given context.
15026 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000015027 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015028 * the caller has to free the object.
15029 */
15030xmlXPathObjectPtr
15031xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15032 xmlXPathParserContextPtr ctxt;
15033 xmlXPathObjectPtr res, tmp, init = NULL;
15034 int stack = 0;
15035
William M. Brackf13f77f2004-11-12 16:03:48 +000015036 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015037
William M. Brackf13f77f2004-11-12 16:03:48 +000015038 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015039
15040 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000015041 if (ctxt == NULL)
15042 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015043 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015044
15045 if (ctxt->value == NULL) {
15046 xmlGenericError(xmlGenericErrorContext,
15047 "xmlXPathEval: evaluation failed\n");
15048 res = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015049 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
Daniel Veillard56de87e2005-02-16 00:22:29 +000015050#ifdef XPATH_STREAMING
15051 && (ctxt->comp->stream == NULL)
15052#endif
15053 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015054 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15055 res = NULL;
15056 } else {
15057 res = valuePop(ctxt);
15058 }
15059
15060 do {
15061 tmp = valuePop(ctxt);
15062 if (tmp != NULL) {
15063 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015064 stack++;
15065 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015066 }
15067 } while (tmp != NULL);
15068 if ((stack != 0) && (res != NULL)) {
15069 xmlGenericError(xmlGenericErrorContext,
15070 "xmlXPathEval: %d object left on the stack\n",
15071 stack);
15072 }
15073 if (ctxt->error != XPATH_EXPRESSION_OK) {
15074 xmlXPathFreeObject(res);
15075 res = NULL;
15076 }
15077
Owen Taylor3473f882001-02-23 17:55:21 +000015078 xmlXPathFreeParserContext(ctxt);
15079 return(res);
15080}
15081
15082/**
15083 * xmlXPathEvalExpression:
15084 * @str: the XPath expression
15085 * @ctxt: the XPath context
15086 *
15087 * Evaluate the XPath expression in the given context.
15088 *
15089 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15090 * the caller has to free the object.
15091 */
15092xmlXPathObjectPtr
15093xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15094 xmlXPathParserContextPtr pctxt;
15095 xmlXPathObjectPtr res, tmp;
15096 int stack = 0;
15097
William M. Brackf13f77f2004-11-12 16:03:48 +000015098 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000015099
William M. Brackf13f77f2004-11-12 16:03:48 +000015100 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000015101
15102 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000015103 if (pctxt == NULL)
15104 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000015105 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000015106
Daniel Veillardc465ffc2006-10-17 19:39:33 +000015107 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000015108 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15109 res = NULL;
15110 } else {
15111 res = valuePop(pctxt);
15112 }
15113 do {
15114 tmp = valuePop(pctxt);
15115 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015116 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000015117 stack++;
15118 }
15119 } while (tmp != NULL);
15120 if ((stack != 0) && (res != NULL)) {
15121 xmlGenericError(xmlGenericErrorContext,
15122 "xmlXPathEvalExpression: %d object left on the stack\n",
15123 stack);
15124 }
15125 xmlXPathFreeParserContext(pctxt);
15126 return(res);
15127}
15128
Daniel Veillard42766c02002-08-22 20:52:17 +000015129/************************************************************************
15130 * *
15131 * Extra functions not pertaining to the XPath spec *
15132 * *
15133 ************************************************************************/
15134/**
15135 * xmlXPathEscapeUriFunction:
15136 * @ctxt: the XPath Parser context
15137 * @nargs: the number of arguments
15138 *
15139 * Implement the escape-uri() XPath function
15140 * string escape-uri(string $str, bool $escape-reserved)
15141 *
15142 * This function applies the URI escaping rules defined in section 2 of [RFC
15143 * 2396] to the string supplied as $uri-part, which typically represents all
15144 * or part of a URI. The effect of the function is to replace any special
15145 * character in the string by an escape sequence of the form %xx%yy...,
15146 * where xxyy... is the hexadecimal representation of the octets used to
15147 * represent the character in UTF-8.
15148 *
15149 * The set of characters that are escaped depends on the setting of the
15150 * boolean argument $escape-reserved.
15151 *
15152 * If $escape-reserved is true, all characters are escaped other than lower
15153 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15154 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15155 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15156 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15157 * A-F).
15158 *
15159 * If $escape-reserved is false, the behavior differs in that characters
15160 * referred to in [RFC 2396] as reserved characters are not escaped. These
15161 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015162 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015163 * [RFC 2396] does not define whether escaped URIs should use lower case or
15164 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15165 * compared using string comparison functions, this function must always use
15166 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015167 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015168 * Generally, $escape-reserved should be set to true when escaping a string
15169 * that is to form a single part of a URI, and to false when escaping an
15170 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015171 *
15172 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015173 * utf-8 and then converted according to RFC 2396.
15174 *
15175 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015176 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015177 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15178 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15179 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15180 *
15181 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015182static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015183xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15184 xmlXPathObjectPtr str;
15185 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080015186 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000015187 xmlChar *cptr;
15188 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015189
Daniel Veillard42766c02002-08-22 20:52:17 +000015190 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015191
Daniel Veillard42766c02002-08-22 20:52:17 +000015192 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015193
Daniel Veillard42766c02002-08-22 20:52:17 +000015194 CAST_TO_STRING;
15195 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015196
Daniel Veillardade10f22012-07-12 09:43:27 +080015197 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015198
Daniel Veillard42766c02002-08-22 20:52:17 +000015199 escape[0] = '%';
15200 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015201
Daniel Veillard42766c02002-08-22 20:52:17 +000015202 if (target) {
15203 for (cptr = str->stringval; *cptr; cptr++) {
15204 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15205 (*cptr >= 'a' && *cptr <= 'z') ||
15206 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015207 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015208 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15209 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015210 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015211 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15212 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15213 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15214 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15215 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15216 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15217 (!escape_reserved &&
15218 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15219 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15220 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15221 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080015222 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000015223 } else {
15224 if ((*cptr >> 4) < 10)
15225 escape[1] = '0' + (*cptr >> 4);
15226 else
15227 escape[1] = 'A' - 10 + (*cptr >> 4);
15228 if ((*cptr & 0xF) < 10)
15229 escape[2] = '0' + (*cptr & 0xF);
15230 else
15231 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015232
Daniel Veillardade10f22012-07-12 09:43:27 +080015233 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000015234 }
15235 }
15236 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015237 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080015238 xmlBufContent(target)));
15239 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015240 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015241}
15242
Owen Taylor3473f882001-02-23 17:55:21 +000015243/**
15244 * xmlXPathRegisterAllFunctions:
15245 * @ctxt: the XPath context
15246 *
15247 * Registers all default XPath functions in this context
15248 */
15249void
15250xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15251{
15252 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15253 xmlXPathBooleanFunction);
15254 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15255 xmlXPathCeilingFunction);
15256 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15257 xmlXPathCountFunction);
15258 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15259 xmlXPathConcatFunction);
15260 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15261 xmlXPathContainsFunction);
15262 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15263 xmlXPathIdFunction);
15264 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15265 xmlXPathFalseFunction);
15266 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15267 xmlXPathFloorFunction);
15268 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15269 xmlXPathLastFunction);
15270 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15271 xmlXPathLangFunction);
15272 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15273 xmlXPathLocalNameFunction);
15274 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15275 xmlXPathNotFunction);
15276 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15277 xmlXPathNameFunction);
15278 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15279 xmlXPathNamespaceURIFunction);
15280 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15281 xmlXPathNormalizeFunction);
15282 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15283 xmlXPathNumberFunction);
15284 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15285 xmlXPathPositionFunction);
15286 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15287 xmlXPathRoundFunction);
15288 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15289 xmlXPathStringFunction);
15290 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15291 xmlXPathStringLengthFunction);
15292 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15293 xmlXPathStartsWithFunction);
15294 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15295 xmlXPathSubstringFunction);
15296 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15297 xmlXPathSubstringBeforeFunction);
15298 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15299 xmlXPathSubstringAfterFunction);
15300 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15301 xmlXPathSumFunction);
15302 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15303 xmlXPathTrueFunction);
15304 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15305 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015306
15307 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15308 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15309 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015310}
15311
15312#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015313#define bottom_xpath
15314#include "elfgcchack.h"